Merge branch 'development'
* development: update readme Add compress to NSDictionary to option method add note about voip Add compress option Fix cocoapods add missing updates Update websocket
This commit is contained in:
commit
6a8a5dc24a
@ -1,5 +1,9 @@
|
|||||||
import PackageDescription
|
import PackageDescription
|
||||||
|
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "SocketIO"
|
name: "SocketIO",
|
||||||
|
dependencies: [
|
||||||
|
.Package(url: "https://github.com/daltoniam/zlib-spm.git", majorVersion: 1),
|
||||||
|
.Package(url: "https://github.com/daltoniam/common-crypto-spm.git", majorVersion: 1)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
10
README.md
10
README.md
@ -7,7 +7,7 @@ Socket.IO-client for iOS/OS X.
|
|||||||
```swift
|
```swift
|
||||||
import SocketIO
|
import SocketIO
|
||||||
|
|
||||||
let socket = SocketIOClient(socketURL: URL(string: "http://localhost:8080")!, config: [.log(true), .forcePolling(true)])
|
let socket = SocketIOClient(socketURL: URL(string: "http://localhost:8080")!, config: [.log(true), .compress])
|
||||||
|
|
||||||
socket.on(clientEvent: .connect) {data, ack in
|
socket.on(clientEvent: .connect) {data, ack in
|
||||||
print("socket connected")
|
print("socket connected")
|
||||||
@ -30,7 +30,7 @@ socket.connect()
|
|||||||
```objective-c
|
```objective-c
|
||||||
@import SocketIO;
|
@import SocketIO;
|
||||||
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost:8080"];
|
NSURL* url = [[NSURL alloc] initWithString:@"http://localhost:8080"];
|
||||||
SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:url config:@{@"log": @YES, @"forcePolling": @YES}];
|
SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:url config:@{@"log": @YES, @"compress": @YES}];
|
||||||
|
|
||||||
[socket on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
|
[socket on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) {
|
||||||
NSLog(@"socket connected");
|
NSLog(@"socket connected");
|
||||||
@ -92,7 +92,7 @@ Then import `import SocketIO`.
|
|||||||
### Carthage
|
### Carthage
|
||||||
Add this line to your `Cartfile`:
|
Add this line to your `Cartfile`:
|
||||||
```
|
```
|
||||||
github "socketio/socket.io-client-swift" ~> 10.0.1 # Or latest version
|
github "socketio/socket.io-client-swift" ~> 10.1.0 # Or latest version
|
||||||
```
|
```
|
||||||
|
|
||||||
Run `carthage update --platform ios,macosx`.
|
Run `carthage update --platform ios,macosx`.
|
||||||
@ -104,7 +104,7 @@ Create `Podfile` and add `pod 'Socket.IO-Client-Swift'`:
|
|||||||
use_frameworks!
|
use_frameworks!
|
||||||
|
|
||||||
target 'YourApp' do
|
target 'YourApp' do
|
||||||
pod 'Socket.IO-Client-Swift', '~> 10.0.1' # Or latest version
|
pod 'Socket.IO-Client-Swift', '~> 10.1.0' # Or latest version
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ Objective-C:
|
|||||||
Add this line to your `Seedfile`:
|
Add this line to your `Seedfile`:
|
||||||
|
|
||||||
```
|
```
|
||||||
github "socketio/socket.io-client-swift", "v10.0.1", :files => "Source/*.swift" # Or latest version
|
github "socketio/socket.io-client-swift", "v10.1.0", :files => "Source/*.swift" # Or latest version
|
||||||
```
|
```
|
||||||
|
|
||||||
Run `seed install`.
|
Run `seed install`.
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = "Socket.IO-Client-Swift"
|
s.name = "Socket.IO-Client-Swift"
|
||||||
s.module_name = "SocketIO"
|
s.module_name = "SocketIO"
|
||||||
s.version = "10.0.1"
|
s.version = "10.1.0"
|
||||||
s.summary = "Socket.IO-client for iOS and OS X"
|
s.summary = "Socket.IO-client for iOS and OS X"
|
||||||
s.description = <<-DESC
|
s.description = <<-DESC
|
||||||
Socket.IO-client for iOS and OS X.
|
Socket.IO-client for iOS and OS X.
|
||||||
@ -14,9 +14,14 @@ Pod::Spec.new do |s|
|
|||||||
s.ios.deployment_target = '8.0'
|
s.ios.deployment_target = '8.0'
|
||||||
s.osx.deployment_target = '10.10'
|
s.osx.deployment_target = '10.10'
|
||||||
s.tvos.deployment_target = '9.0'
|
s.tvos.deployment_target = '9.0'
|
||||||
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v10.0.1' }
|
s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v10.1.0' }
|
||||||
s.source_files = "Source/**/*.swift"
|
s.source_files = "Source/**/*.swift"
|
||||||
|
s.libraries = 'z'
|
||||||
|
s.preserve_paths = 'zlib/*'
|
||||||
s.requires_arc = true
|
s.requires_arc = true
|
||||||
s.pod_target_xcconfig = {'SWIFT_VERSION' => '3.1'}
|
s.pod_target_xcconfig = {
|
||||||
|
'SWIFT_VERSION' => '3.1',
|
||||||
|
'SWIFT_INCLUDE_PATHS' => '$(PODS_ROOT)/Socket.IO-Client-Swift/zlib'
|
||||||
|
}
|
||||||
# s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files
|
# s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files
|
||||||
end
|
end
|
||||||
|
|||||||
@ -99,6 +99,16 @@
|
|||||||
74BC45AB1D0C6675008CC431 /* SocketClientManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74BC45AA1D0C6675008CC431 /* SocketClientManager.swift */; };
|
74BC45AB1D0C6675008CC431 /* SocketClientManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74BC45AA1D0C6675008CC431 /* SocketClientManager.swift */; };
|
||||||
74BC45AC1D0C6675008CC431 /* SocketClientManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74BC45AA1D0C6675008CC431 /* SocketClientManager.swift */; };
|
74BC45AC1D0C6675008CC431 /* SocketClientManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74BC45AA1D0C6675008CC431 /* SocketClientManager.swift */; };
|
||||||
74BC45AD1D0C6675008CC431 /* SocketClientManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74BC45AA1D0C6675008CC431 /* SocketClientManager.swift */; };
|
74BC45AD1D0C6675008CC431 /* SocketClientManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74BC45AA1D0C6675008CC431 /* SocketClientManager.swift */; };
|
||||||
|
74DA216E1F0943EE009C19EE /* include.h in Headers */ = {isa = PBXBuildFile; fileRef = 74DA216C1F09438D009C19EE /* include.h */; };
|
||||||
|
74DA216F1F0943F4009C19EE /* include.h in Headers */ = {isa = PBXBuildFile; fileRef = 74DA216C1F09438D009C19EE /* include.h */; };
|
||||||
|
74DA21701F0943F8009C19EE /* include.h in Headers */ = {isa = PBXBuildFile; fileRef = 74DA216C1F09438D009C19EE /* include.h */; };
|
||||||
|
74DA21721F094408009C19EE /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 74DA21711F094408009C19EE /* libz.tbd */; };
|
||||||
|
74DA21741F09440F009C19EE /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 74DA21731F09440F009C19EE /* libz.tbd */; };
|
||||||
|
74DA21761F094417009C19EE /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 74DA21751F094417009C19EE /* libz.tbd */; };
|
||||||
|
74DA217C1F09457B009C19EE /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 74DA21731F09440F009C19EE /* libz.tbd */; };
|
||||||
|
74DA21811F094887009C19EE /* Compression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74DA21801F094887009C19EE /* Compression.swift */; };
|
||||||
|
74DA21821F094887009C19EE /* Compression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74DA21801F094887009C19EE /* Compression.swift */; };
|
||||||
|
74DA21831F094887009C19EE /* Compression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74DA21801F094887009C19EE /* Compression.swift */; };
|
||||||
74F124F01BC574CF002966F4 /* SocketBasicPacketTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124EF1BC574CF002966F4 /* SocketBasicPacketTest.swift */; };
|
74F124F01BC574CF002966F4 /* SocketBasicPacketTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124EF1BC574CF002966F4 /* SocketBasicPacketTest.swift */; };
|
||||||
74F124F11BC574CF002966F4 /* SocketBasicPacketTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124EF1BC574CF002966F4 /* SocketBasicPacketTest.swift */; };
|
74F124F11BC574CF002966F4 /* SocketBasicPacketTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124EF1BC574CF002966F4 /* SocketBasicPacketTest.swift */; };
|
||||||
CEBA569A1CDA0B8200BA0389 /* SocketExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEBA56991CDA0B8200BA0389 /* SocketExtensions.swift */; };
|
CEBA569A1CDA0B8200BA0389 /* SocketExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEBA56991CDA0B8200BA0389 /* SocketExtensions.swift */; };
|
||||||
@ -175,6 +185,13 @@
|
|||||||
749642B41D3FCE5500DD32D1 /* WebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebSocket.swift; path = Source/WebSocket.swift; sourceTree = "<group>"; };
|
749642B41D3FCE5500DD32D1 /* WebSocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WebSocket.swift; path = Source/WebSocket.swift; sourceTree = "<group>"; };
|
||||||
74ABF7761C3991C10078C657 /* SocketIOClientSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketIOClientSpec.swift; path = Source/SocketIOClientSpec.swift; sourceTree = "<group>"; };
|
74ABF7761C3991C10078C657 /* SocketIOClientSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketIOClientSpec.swift; path = Source/SocketIOClientSpec.swift; sourceTree = "<group>"; };
|
||||||
74BC45AA1D0C6675008CC431 /* SocketClientManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketClientManager.swift; path = Source/SocketClientManager.swift; sourceTree = "<group>"; };
|
74BC45AA1D0C6675008CC431 /* SocketClientManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketClientManager.swift; path = Source/SocketClientManager.swift; sourceTree = "<group>"; };
|
||||||
|
74DA216C1F09438D009C19EE /* include.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = include.h; path = zlib/include.h; sourceTree = "<group>"; };
|
||||||
|
74DA21711F094408009C19EE /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; };
|
||||||
|
74DA21731F09440F009C19EE /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||||
|
74DA21751F094417009C19EE /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS10.2.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; };
|
||||||
|
74DA21771F09444E009C19EE /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; name = module.modulemap; path = zlib/module.modulemap; sourceTree = "<group>"; };
|
||||||
|
74DA217D1F0945E9009C19EE /* libcommonCrypto.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcommonCrypto.tbd; path = usr/lib/system/libcommonCrypto.tbd; sourceTree = SDKROOT; };
|
||||||
|
74DA21801F094887009C19EE /* Compression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Compression.swift; path = Source/Compression.swift; sourceTree = "<group>"; };
|
||||||
74F124EF1BC574CF002966F4 /* SocketBasicPacketTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketBasicPacketTest.swift; sourceTree = "<group>"; };
|
74F124EF1BC574CF002966F4 /* SocketBasicPacketTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketBasicPacketTest.swift; sourceTree = "<group>"; };
|
||||||
CEBA56991CDA0B8200BA0389 /* SocketExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketExtensions.swift; path = Source/SocketExtensions.swift; sourceTree = "<group>"; };
|
CEBA56991CDA0B8200BA0389 /* SocketExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketExtensions.swift; path = Source/SocketExtensions.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
@ -184,6 +201,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
74DA21721F094408009C19EE /* libz.tbd in Frameworks */,
|
||||||
6CA08A961D615C040061FD2A /* Security.framework in Frameworks */,
|
6CA08A961D615C040061FD2A /* Security.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@ -200,6 +218,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
74DA21741F09440F009C19EE /* libz.tbd in Frameworks */,
|
||||||
6CA08A981D615C0B0061FD2A /* Security.framework in Frameworks */,
|
6CA08A981D615C0B0061FD2A /* Security.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@ -208,6 +227,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
74DA217C1F09457B009C19EE /* libz.tbd in Frameworks */,
|
||||||
572EF2431B51F18A00EEBB58 /* SocketIO.framework in Frameworks */,
|
572EF2431B51F18A00EEBB58 /* SocketIO.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@ -216,6 +236,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
74DA21761F094417009C19EE /* libz.tbd in Frameworks */,
|
||||||
6CA08A9A1D615C140061FD2A /* Security.framework in Frameworks */,
|
6CA08A9A1D615C140061FD2A /* Security.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@ -234,6 +255,7 @@
|
|||||||
572EF20D1B51F12F00EEBB58 = {
|
572EF20D1B51F12F00EEBB58 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
74DA216B1F094371009C19EE /* zlib */,
|
||||||
6CA08A9B1D615C190061FD2A /* Frameworks */,
|
6CA08A9B1D615C190061FD2A /* Frameworks */,
|
||||||
572EF21A1B51F16C00EEBB58 /* Products */,
|
572EF21A1B51F16C00EEBB58 /* Products */,
|
||||||
572EF21B1B51F16C00EEBB58 /* SocketIO-iOS */,
|
572EF21B1B51F16C00EEBB58 /* SocketIO-iOS */,
|
||||||
@ -347,6 +369,10 @@
|
|||||||
6CA08A9B1D615C190061FD2A /* Frameworks */ = {
|
6CA08A9B1D615C190061FD2A /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
74DA217D1F0945E9009C19EE /* libcommonCrypto.tbd */,
|
||||||
|
74DA21751F094417009C19EE /* libz.tbd */,
|
||||||
|
74DA21731F09440F009C19EE /* libz.tbd */,
|
||||||
|
74DA21711F094408009C19EE /* libz.tbd */,
|
||||||
6CA08A9E1D615C340061FD2A /* tvOS */,
|
6CA08A9E1D615C340061FD2A /* tvOS */,
|
||||||
6CA08A9D1D615C2C0061FD2A /* Mac */,
|
6CA08A9D1D615C2C0061FD2A /* Mac */,
|
||||||
6CA08A9C1D615C270061FD2A /* iOS */,
|
6CA08A9C1D615C270061FD2A /* iOS */,
|
||||||
@ -381,12 +407,22 @@
|
|||||||
74B4AD1B1D09A5C30062A523 /* Websocket */ = {
|
74B4AD1B1D09A5C30062A523 /* Websocket */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
74DA21801F094887009C19EE /* Compression.swift */,
|
||||||
749642B31D3FCE5500DD32D1 /* SSLSecurity.swift */,
|
749642B31D3FCE5500DD32D1 /* SSLSecurity.swift */,
|
||||||
749642B41D3FCE5500DD32D1 /* WebSocket.swift */,
|
749642B41D3FCE5500DD32D1 /* WebSocket.swift */,
|
||||||
);
|
);
|
||||||
name = Websocket;
|
name = Websocket;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
74DA216B1F094371009C19EE /* zlib */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
74DA216C1F09438D009C19EE /* include.h */,
|
||||||
|
74DA21771F09444E009C19EE /* module.modulemap */,
|
||||||
|
);
|
||||||
|
name = zlib;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXHeadersBuildPhase section */
|
/* Begin PBXHeadersBuildPhase section */
|
||||||
@ -395,6 +431,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
572EF21F1B51F16C00EEBB58 /* SocketIO.h in Headers */,
|
572EF21F1B51F16C00EEBB58 /* SocketIO.h in Headers */,
|
||||||
|
74DA21701F0943F8009C19EE /* include.h in Headers */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -403,6 +440,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
572EF23D1B51F18A00EEBB58 /* SocketIO-Mac.h in Headers */,
|
572EF23D1B51F18A00EEBB58 /* SocketIO-Mac.h in Headers */,
|
||||||
|
74DA216F1F0943F4009C19EE /* include.h in Headers */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -411,6 +449,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
57634A111BD9B46A00E19CD7 /* SocketIO.h in Headers */,
|
57634A111BD9B46A00E19CD7 /* SocketIO.h in Headers */,
|
||||||
|
74DA216E1F0943EE009C19EE /* include.h in Headers */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -643,6 +682,7 @@
|
|||||||
749642B51D3FCE5500DD32D1 /* SSLSecurity.swift in Sources */,
|
749642B51D3FCE5500DD32D1 /* SSLSecurity.swift in Sources */,
|
||||||
74171EB71C10CD240062D398 /* SocketParsable.swift in Sources */,
|
74171EB71C10CD240062D398 /* SocketParsable.swift in Sources */,
|
||||||
74171E811C10CD240062D398 /* SocketEnginePacketType.swift in Sources */,
|
74171E811C10CD240062D398 /* SocketEnginePacketType.swift in Sources */,
|
||||||
|
74DA21811F094887009C19EE /* Compression.swift in Sources */,
|
||||||
74171E6F1C10CD240062D398 /* SocketAnyEvent.swift in Sources */,
|
74171E6F1C10CD240062D398 /* SocketAnyEvent.swift in Sources */,
|
||||||
747BC5991D5F943500CA5FA4 /* SocketIOClientConfiguration.swift in Sources */,
|
747BC5991D5F943500CA5FA4 /* SocketIOClientConfiguration.swift in Sources */,
|
||||||
74171E9F1C10CD240062D398 /* SocketIOClientOption.swift in Sources */,
|
74171E9F1C10CD240062D398 /* SocketIOClientOption.swift in Sources */,
|
||||||
@ -685,6 +725,7 @@
|
|||||||
749642B61D3FCE5500DD32D1 /* SSLSecurity.swift in Sources */,
|
749642B61D3FCE5500DD32D1 /* SSLSecurity.swift in Sources */,
|
||||||
74171EB91C10CD240062D398 /* SocketParsable.swift in Sources */,
|
74171EB91C10CD240062D398 /* SocketParsable.swift in Sources */,
|
||||||
74171E831C10CD240062D398 /* SocketEnginePacketType.swift in Sources */,
|
74171E831C10CD240062D398 /* SocketEnginePacketType.swift in Sources */,
|
||||||
|
74DA21821F094887009C19EE /* Compression.swift in Sources */,
|
||||||
74171E711C10CD240062D398 /* SocketAnyEvent.swift in Sources */,
|
74171E711C10CD240062D398 /* SocketAnyEvent.swift in Sources */,
|
||||||
747BC59A1D5F943500CA5FA4 /* SocketIOClientConfiguration.swift in Sources */,
|
747BC59A1D5F943500CA5FA4 /* SocketIOClientConfiguration.swift in Sources */,
|
||||||
74171EA11C10CD240062D398 /* SocketIOClientOption.swift in Sources */,
|
74171EA11C10CD240062D398 /* SocketIOClientOption.swift in Sources */,
|
||||||
@ -731,6 +772,7 @@
|
|||||||
749642B71D3FCE5500DD32D1 /* SSLSecurity.swift in Sources */,
|
749642B71D3FCE5500DD32D1 /* SSLSecurity.swift in Sources */,
|
||||||
74171EBB1C10CD240062D398 /* SocketParsable.swift in Sources */,
|
74171EBB1C10CD240062D398 /* SocketParsable.swift in Sources */,
|
||||||
74171E851C10CD240062D398 /* SocketEnginePacketType.swift in Sources */,
|
74171E851C10CD240062D398 /* SocketEnginePacketType.swift in Sources */,
|
||||||
|
74DA21831F094887009C19EE /* Compression.swift in Sources */,
|
||||||
74171E731C10CD240062D398 /* SocketAnyEvent.swift in Sources */,
|
74171E731C10CD240062D398 /* SocketAnyEvent.swift in Sources */,
|
||||||
747BC59B1D5F943500CA5FA4 /* SocketIOClientConfiguration.swift in Sources */,
|
747BC59B1D5F943500CA5FA4 /* SocketIOClientConfiguration.swift in Sources */,
|
||||||
74171EA31C10CD240062D398 /* SocketIOClientOption.swift in Sources */,
|
74171EA31C10CD240062D398 /* SocketIOClientOption.swift in Sources */,
|
||||||
@ -885,6 +927,7 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = io.socket.SocketIOClientSwift;
|
PRODUCT_BUNDLE_IDENTIFIER = io.socket.SocketIOClientSwift;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_INCLUDE_PATHS = $SRCROOT/zlib;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 3.0;
|
SWIFT_VERSION = 3.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
@ -937,6 +980,7 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = io.socket.SocketIOClientSwift;
|
PRODUCT_BUNDLE_IDENTIFIER = io.socket.SocketIOClientSwift;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_INCLUDE_PATHS = $SRCROOT/zlib;
|
||||||
SWIFT_VERSION = 3.0;
|
SWIFT_VERSION = 3.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
@ -1088,11 +1132,16 @@
|
|||||||
INFOPLIST_FILE = "SocketIO-Mac/Info.plist";
|
INFOPLIST_FILE = "SocketIO-Mac/Info.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(SDKROOT)/usr/lib/system",
|
||||||
|
);
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)";
|
PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)";
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_INCLUDE_PATHS = $SRCROOT/zlib;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 3.0;
|
SWIFT_VERSION = 3.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
@ -1142,10 +1191,15 @@
|
|||||||
INFOPLIST_FILE = "SocketIO-Mac/Info.plist";
|
INFOPLIST_FILE = "SocketIO-Mac/Info.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(SDKROOT)/usr/lib/system",
|
||||||
|
);
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)";
|
PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)";
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_INCLUDE_PATHS = $SRCROOT/zlib;
|
||||||
SWIFT_VERSION = 3.0;
|
SWIFT_VERSION = 3.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
VERSION_INFO_PREFIX = "";
|
VERSION_INFO_PREFIX = "";
|
||||||
@ -1196,6 +1250,10 @@
|
|||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
INFOPLIST_FILE = "SocketIO-MacTests/Info.plist";
|
INFOPLIST_FILE = "SocketIO-MacTests/Info.plist";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(SDKROOT)/usr/lib/system",
|
||||||
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
@ -1245,6 +1303,10 @@
|
|||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
INFOPLIST_FILE = "SocketIO-MacTests/Info.plist";
|
INFOPLIST_FILE = "SocketIO-MacTests/Info.plist";
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"$(SDKROOT)/usr/lib/system",
|
||||||
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)";
|
PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)";
|
||||||
@ -1304,6 +1366,7 @@
|
|||||||
PRODUCT_NAME = SocketIO;
|
PRODUCT_NAME = SocketIO;
|
||||||
SDKROOT = appletvos;
|
SDKROOT = appletvos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_INCLUDE_PATHS = $SRCROOT/zlib;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
TARGETED_DEVICE_FAMILY = 3;
|
TARGETED_DEVICE_FAMILY = 3;
|
||||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
@ -1356,6 +1419,7 @@
|
|||||||
PRODUCT_NAME = SocketIO;
|
PRODUCT_NAME = SocketIO;
|
||||||
SDKROOT = appletvos;
|
SDKROOT = appletvos;
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_INCLUDE_PATHS = $SRCROOT/zlib;
|
||||||
TARGETED_DEVICE_FAMILY = 3;
|
TARGETED_DEVICE_FAMILY = 3;
|
||||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
|
|||||||
174
Source/Compression.swift
Normal file
174
Source/Compression.swift
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Compression.swift
|
||||||
|
//
|
||||||
|
// Created by Joseph Ross on 7/16/14.
|
||||||
|
// Copyright © 2017 Joseph Ross.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Compression implementation is implemented in conformance with RFC 7692 Compression Extensions
|
||||||
|
// for WebSocket: https://tools.ietf.org/html/rfc7692
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
import Foundation
|
||||||
|
import zlib
|
||||||
|
|
||||||
|
class Decompressor {
|
||||||
|
private var strm = z_stream()
|
||||||
|
private var buffer = [UInt8](repeating: 0, count: 0x2000)
|
||||||
|
private var inflateInitialized = false
|
||||||
|
private let windowBits:Int
|
||||||
|
|
||||||
|
init?(windowBits:Int) {
|
||||||
|
self.windowBits = windowBits
|
||||||
|
guard initInflate() else { return nil }
|
||||||
|
}
|
||||||
|
|
||||||
|
private func initInflate() -> Bool {
|
||||||
|
if Z_OK == inflateInit2_(&strm, -CInt(windowBits),
|
||||||
|
ZLIB_VERSION, CInt(MemoryLayout<z_stream>.size))
|
||||||
|
{
|
||||||
|
inflateInitialized = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func reset() throws {
|
||||||
|
teardownInflate()
|
||||||
|
guard initInflate() else { throw NSError() }
|
||||||
|
}
|
||||||
|
|
||||||
|
func decompress(_ data: Data, finish: Bool) throws -> Data {
|
||||||
|
return try data.withUnsafeBytes { (bytes:UnsafePointer<UInt8>) -> Data in
|
||||||
|
return try decompress(bytes: bytes, count: data.count, finish: finish)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func decompress(bytes: UnsafePointer<UInt8>, count: Int, finish: Bool) throws -> Data {
|
||||||
|
var decompressed = Data()
|
||||||
|
try decompress(bytes: bytes, count: count, out: &decompressed)
|
||||||
|
|
||||||
|
if finish {
|
||||||
|
let tail:[UInt8] = [0x00, 0x00, 0xFF, 0xFF]
|
||||||
|
try decompress(bytes: tail, count: tail.count, out: &decompressed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return decompressed
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private func decompress(bytes: UnsafePointer<UInt8>, count: Int, out:inout Data) throws {
|
||||||
|
var res:CInt = 0
|
||||||
|
strm.next_in = UnsafeMutablePointer<UInt8>(mutating: bytes)
|
||||||
|
strm.avail_in = CUnsignedInt(count)
|
||||||
|
|
||||||
|
repeat {
|
||||||
|
strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
|
||||||
|
strm.avail_out = CUnsignedInt(buffer.count)
|
||||||
|
|
||||||
|
res = inflate(&strm, 0)
|
||||||
|
|
||||||
|
let byteCount = buffer.count - Int(strm.avail_out)
|
||||||
|
out.append(buffer, count: byteCount)
|
||||||
|
} while res == Z_OK && strm.avail_out == 0
|
||||||
|
|
||||||
|
guard (res == Z_OK && strm.avail_out > 0)
|
||||||
|
|| (res == Z_BUF_ERROR && Int(strm.avail_out) == buffer.count)
|
||||||
|
else {
|
||||||
|
throw NSError(domain: WebSocket.ErrorDomain, code: Int(WebSocket.InternalErrorCode.compressionError.rawValue), userInfo: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func teardownInflate() {
|
||||||
|
if inflateInitialized, Z_OK == inflateEnd(&strm) {
|
||||||
|
inflateInitialized = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
teardownInflate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Compressor {
|
||||||
|
private var strm = z_stream()
|
||||||
|
private var buffer = [UInt8](repeating: 0, count: 0x2000)
|
||||||
|
private var deflateInitialized = false
|
||||||
|
private let windowBits:Int
|
||||||
|
|
||||||
|
init?(windowBits: Int) {
|
||||||
|
self.windowBits = windowBits
|
||||||
|
guard initDeflate() else { return nil }
|
||||||
|
}
|
||||||
|
|
||||||
|
private func initDeflate() -> Bool {
|
||||||
|
if Z_OK == deflateInit2_(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
|
||||||
|
-CInt(windowBits), 8, Z_DEFAULT_STRATEGY,
|
||||||
|
ZLIB_VERSION, CInt(MemoryLayout<z_stream>.size))
|
||||||
|
{
|
||||||
|
deflateInitialized = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func reset() throws {
|
||||||
|
teardownDeflate()
|
||||||
|
guard initDeflate() else { throw NSError() }
|
||||||
|
}
|
||||||
|
|
||||||
|
func compress(_ data: Data) throws -> Data {
|
||||||
|
var compressed = Data()
|
||||||
|
var res:CInt = 0
|
||||||
|
data.withUnsafeBytes { (ptr:UnsafePointer<UInt8>) -> Void in
|
||||||
|
strm.next_in = UnsafeMutablePointer<UInt8>(mutating: ptr)
|
||||||
|
strm.avail_in = CUnsignedInt(data.count)
|
||||||
|
|
||||||
|
repeat {
|
||||||
|
strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
|
||||||
|
strm.avail_out = CUnsignedInt(buffer.count)
|
||||||
|
|
||||||
|
res = deflate(&strm, Z_SYNC_FLUSH)
|
||||||
|
|
||||||
|
let byteCount = buffer.count - Int(strm.avail_out)
|
||||||
|
compressed.append(buffer, count: byteCount)
|
||||||
|
}
|
||||||
|
while res == Z_OK && strm.avail_out == 0
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
guard res == Z_OK && strm.avail_out > 0
|
||||||
|
|| (res == Z_BUF_ERROR && Int(strm.avail_out) == buffer.count)
|
||||||
|
else {
|
||||||
|
throw NSError(domain: WebSocket.ErrorDomain, code: Int(WebSocket.InternalErrorCode.compressionError.rawValue), userInfo: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
compressed.removeLast(4)
|
||||||
|
return compressed
|
||||||
|
}
|
||||||
|
|
||||||
|
private func teardownDeflate() {
|
||||||
|
if deflateInitialized, Z_OK == deflateEnd(&strm) {
|
||||||
|
deflateInitialized = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
teardownDeflate()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -60,6 +60,9 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
|
|||||||
/// `true` if this engine is closed.
|
/// `true` if this engine is closed.
|
||||||
public private(set) var closed = false
|
public private(set) var closed = false
|
||||||
|
|
||||||
|
/// If `true` the engine will attempt to use WebSocket compression.
|
||||||
|
public private(set) var compress = false
|
||||||
|
|
||||||
/// `true` if this engine is connected. Connected means that the initial poll connect has succeeded.
|
/// `true` if this engine is connected. Connected means that the initial poll connect has succeeded.
|
||||||
public private(set) var connected = false
|
public private(set) var connected = false
|
||||||
|
|
||||||
@ -131,7 +134,6 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
|
|||||||
private var secure = false
|
private var secure = false
|
||||||
private var security: SSLSecurity?
|
private var security: SSLSecurity?
|
||||||
private var selfSigned = false
|
private var selfSigned = false
|
||||||
private var voipEnabled = false
|
|
||||||
|
|
||||||
// MARK: Initializers
|
// MARK: Initializers
|
||||||
|
|
||||||
@ -163,14 +165,14 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
|
|||||||
if !socketPath.hasSuffix("/") {
|
if !socketPath.hasSuffix("/") {
|
||||||
socketPath += "/"
|
socketPath += "/"
|
||||||
}
|
}
|
||||||
case let .voipEnabled(enable):
|
|
||||||
voipEnabled = enable
|
|
||||||
case let .secure(secure):
|
case let .secure(secure):
|
||||||
self.secure = secure
|
self.secure = secure
|
||||||
case let .selfSigned(selfSigned):
|
case let .selfSigned(selfSigned):
|
||||||
self.selfSigned = selfSigned
|
self.selfSigned = selfSigned
|
||||||
case let .security(security):
|
case let .security(security):
|
||||||
self.security = security
|
self.security = security
|
||||||
|
case .compress:
|
||||||
|
self.compress = true
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -331,7 +333,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll
|
|||||||
}
|
}
|
||||||
|
|
||||||
ws?.callbackQueue = engineQueue
|
ws?.callbackQueue = engineQueue
|
||||||
ws?.voipEnabled = voipEnabled
|
ws?.enableCompression = compress
|
||||||
ws?.delegate = self
|
ws?.delegate = self
|
||||||
ws?.disableSSLCertValidation = selfSigned
|
ws?.disableSSLCertValidation = selfSigned
|
||||||
ws?.security = security
|
ws?.security = security
|
||||||
|
|||||||
@ -80,8 +80,8 @@ extension NSDictionary {
|
|||||||
return .selfSigned(selfSigned)
|
return .selfSigned(selfSigned)
|
||||||
case let ("sessionDelegate", delegate as URLSessionDelegate):
|
case let ("sessionDelegate", delegate as URLSessionDelegate):
|
||||||
return .sessionDelegate(delegate)
|
return .sessionDelegate(delegate)
|
||||||
case let ("voipEnabled", enable as Bool):
|
case let ("compress", compress as Bool):
|
||||||
return .voipEnabled(enable)
|
return compress ? .compress : nil
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,9 @@ protocol ClientOption : CustomStringConvertible, Equatable {
|
|||||||
|
|
||||||
/// The options for a client.
|
/// The options for a client.
|
||||||
public enum SocketIOClientOption : ClientOption {
|
public enum SocketIOClientOption : ClientOption {
|
||||||
|
/// If given, the WebSocket transport will attempt to use compression.
|
||||||
|
case compress
|
||||||
|
|
||||||
/// A dictionary of GET parameters that will be included in the connect url.
|
/// A dictionary of GET parameters that will be included in the connect url.
|
||||||
case connectParams([String: Any])
|
case connectParams([String: Any])
|
||||||
|
|
||||||
@ -94,6 +97,7 @@ public enum SocketIOClientOption : ClientOption {
|
|||||||
|
|
||||||
/// If passed `true`, the WebSocket transport will try and use voip logic to keep network connections open in
|
/// If passed `true`, the WebSocket transport will try and use voip logic to keep network connections open in
|
||||||
/// the background. **This option is experimental as socket.io shouldn't be used for background communication.**
|
/// the background. **This option is experimental as socket.io shouldn't be used for background communication.**
|
||||||
|
@available(*, deprecated, message: "No longer has any effect, and will be removed in v11.0")
|
||||||
case voipEnabled(Bool)
|
case voipEnabled(Bool)
|
||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
@ -103,6 +107,8 @@ public enum SocketIOClientOption : ClientOption {
|
|||||||
let description: String
|
let description: String
|
||||||
|
|
||||||
switch self {
|
switch self {
|
||||||
|
case .compress:
|
||||||
|
description = "compress"
|
||||||
case .connectParams:
|
case .connectParams:
|
||||||
description = "connectParams"
|
description = "connectParams"
|
||||||
case .cookies:
|
case .cookies:
|
||||||
@ -152,6 +158,8 @@ public enum SocketIOClientOption : ClientOption {
|
|||||||
let value: Any
|
let value: Any
|
||||||
|
|
||||||
switch self {
|
switch self {
|
||||||
|
case .compress:
|
||||||
|
value = true
|
||||||
case let .connectParams(params):
|
case let .connectParams(params):
|
||||||
value = params
|
value = params
|
||||||
case let .cookies(cookies):
|
case let .cookies(cookies):
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
import Foundation
|
import Foundation
|
||||||
import CoreFoundation
|
import CoreFoundation
|
||||||
import Security
|
import CommonCrypto
|
||||||
|
|
||||||
public let WebsocketDidConnectNotification = "WebsocketDidConnectNotification"
|
public let WebsocketDidConnectNotification = "WebsocketDidConnectNotification"
|
||||||
public let WebsocketDidDisconnectNotification = "WebsocketDidDisconnectNotification"
|
public let WebsocketDidDisconnectNotification = "WebsocketDidDisconnectNotification"
|
||||||
@ -37,9 +37,19 @@ public protocol WebSocketPongDelegate: class {
|
|||||||
func websocketDidReceivePong(socket: WebSocket, data: Data?)
|
func websocketDidReceivePong(socket: WebSocket, data: Data?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A Delegate with more advanced info on messages and connection etc.
|
||||||
|
public protocol WebSocketAdvancedDelegate: class {
|
||||||
|
func websocketDidConnect(socket: WebSocket)
|
||||||
|
func websocketDidDisconnect(socket: WebSocket, error: NSError?)
|
||||||
|
func websocketDidReceiveMessage(socket: WebSocket, text: String, response: WebSocket.WSResponse)
|
||||||
|
func websocketDidReceiveData(socket: WebSocket, data: Data, response: WebSocket.WSResponse)
|
||||||
|
func websocketHttpUpgrade(socket: WebSocket, request: CFHTTPMessage)
|
||||||
|
func websocketHttpUpgrade(socket: WebSocket, response: CFHTTPMessage)
|
||||||
|
}
|
||||||
|
|
||||||
open class WebSocket : NSObject, StreamDelegate {
|
open class WebSocket : NSObject, StreamDelegate {
|
||||||
|
|
||||||
enum OpCode : UInt8 {
|
public enum OpCode : UInt8 {
|
||||||
case continueFrame = 0x0
|
case continueFrame = 0x0
|
||||||
case textFrame = 0x1
|
case textFrame = 0x1
|
||||||
case binaryFrame = 0x2
|
case binaryFrame = 0x2
|
||||||
@ -68,6 +78,9 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
enum InternalErrorCode: UInt16 {
|
enum InternalErrorCode: UInt16 {
|
||||||
// 0-999 WebSocket status codes not used
|
// 0-999 WebSocket status codes not used
|
||||||
case outputStreamWriteError = 1
|
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.
|
// Where the callback is executed. It defaults to the main UI thread queue.
|
||||||
@ -84,6 +97,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
let headerWSProtocolName = "Sec-WebSocket-Protocol"
|
let headerWSProtocolName = "Sec-WebSocket-Protocol"
|
||||||
let headerWSVersionName = "Sec-WebSocket-Version"
|
let headerWSVersionName = "Sec-WebSocket-Version"
|
||||||
let headerWSVersionValue = "13"
|
let headerWSVersionValue = "13"
|
||||||
|
let headerWSExtensionName = "Sec-WebSocket-Extensions"
|
||||||
let headerWSKeyName = "Sec-WebSocket-Key"
|
let headerWSKeyName = "Sec-WebSocket-Key"
|
||||||
let headerOriginName = "Origin"
|
let headerOriginName = "Origin"
|
||||||
let headerWSAcceptName = "Sec-WebSocket-Accept"
|
let headerWSAcceptName = "Sec-WebSocket-Accept"
|
||||||
@ -91,18 +105,22 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
let FinMask: UInt8 = 0x80
|
let FinMask: UInt8 = 0x80
|
||||||
let OpCodeMask: UInt8 = 0x0F
|
let OpCodeMask: UInt8 = 0x0F
|
||||||
let RSVMask: UInt8 = 0x70
|
let RSVMask: UInt8 = 0x70
|
||||||
|
let RSV1Mask: UInt8 = 0x40
|
||||||
let MaskMask: UInt8 = 0x80
|
let MaskMask: UInt8 = 0x80
|
||||||
let PayloadLenMask: UInt8 = 0x7F
|
let PayloadLenMask: UInt8 = 0x7F
|
||||||
let MaxFrameSize: Int = 32
|
let MaxFrameSize: Int = 32
|
||||||
let httpSwitchProtocolCode = 101
|
let httpSwitchProtocolCode = 101
|
||||||
let supportedSSLSchemes = ["wss", "https"]
|
let supportedSSLSchemes = ["wss", "https"]
|
||||||
|
|
||||||
class WSResponse {
|
public class WSResponse {
|
||||||
var isFin = false
|
var isFin = false
|
||||||
var code: OpCode = .continueFrame
|
public var code: OpCode = .continueFrame
|
||||||
var bytesLeft = 0
|
var bytesLeft = 0
|
||||||
var frameCount = 0
|
public var frameCount = 0
|
||||||
var buffer: NSMutableData?
|
public var buffer: NSMutableData?
|
||||||
|
public let firstFrame = {
|
||||||
|
return Date()
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Delegates
|
// MARK: - Delegates
|
||||||
@ -110,20 +128,46 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
/// and also connection/disconnect messages.
|
/// and also connection/disconnect messages.
|
||||||
public weak var delegate: WebSocketDelegate?
|
public weak var delegate: WebSocketDelegate?
|
||||||
|
|
||||||
|
/// The optional advanced delegate can be used insteadof of the delegate
|
||||||
|
public weak var advancedDelegate: WebSocketAdvancedDelegate?
|
||||||
|
|
||||||
/// Receives a callback for each pong message recived.
|
/// Receives a callback for each pong message recived.
|
||||||
public weak var pongDelegate: WebSocketPongDelegate?
|
public weak var pongDelegate: WebSocketPongDelegate?
|
||||||
|
|
||||||
|
|
||||||
// MARK: - Block based API.
|
// MARK: - Block based API.
|
||||||
|
public enum HTTPMethod {
|
||||||
|
case get
|
||||||
|
case post
|
||||||
|
case put
|
||||||
|
case connect
|
||||||
|
case custom(value: String)
|
||||||
|
var representation: String {
|
||||||
|
switch self {
|
||||||
|
case .get:
|
||||||
|
return "GET"
|
||||||
|
case .post:
|
||||||
|
return "POST"
|
||||||
|
case .put:
|
||||||
|
return "PUT"
|
||||||
|
case .connect:
|
||||||
|
return "CONNECT"
|
||||||
|
case .custom(let value):
|
||||||
|
return value.capitalized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public var onConnect: (() -> Void)?
|
public var onConnect: (() -> Void)?
|
||||||
public var onDisconnect: ((NSError?) -> Void)?
|
public var onDisconnect: ((NSError?) -> Void)?
|
||||||
public var onText: ((String) -> Void)?
|
public var onText: ((String) -> Void)?
|
||||||
public var onData: ((Data) -> Void)?
|
public var onData: ((Data) -> Void)?
|
||||||
public var onPong: ((Data?) -> Void)?
|
public var onPong: ((Data?) -> Void)?
|
||||||
|
|
||||||
|
public var httpMethod: HTTPMethod = .get
|
||||||
public var headers = [String: String]()
|
public var headers = [String: String]()
|
||||||
public var voipEnabled = false
|
|
||||||
public var disableSSLCertValidation = false
|
public var disableSSLCertValidation = false
|
||||||
|
public var enableCompression = true
|
||||||
public var security: SSLTrustValidator?
|
public var security: SSLTrustValidator?
|
||||||
public var enabledSSLCipherSuites: [SSLCipherSuite]?
|
public var enabledSSLCipherSuites: [SSLCipherSuite]?
|
||||||
public var origin: String?
|
public var origin: String?
|
||||||
@ -135,11 +179,24 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
public var currentURL: URL { return url }
|
public var currentURL: URL { return url }
|
||||||
|
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
|
private struct CompressionState {
|
||||||
|
var supportsCompression = false
|
||||||
|
var messageNeedsDecompression = false
|
||||||
|
var serverMaxWindowBits = 15
|
||||||
|
var clientMaxWindowBits = 15
|
||||||
|
var clientNoContextTakeover = false
|
||||||
|
var serverNoContextTakeover = false
|
||||||
|
var decompressor:Decompressor? = nil
|
||||||
|
var compressor:Compressor? = nil
|
||||||
|
}
|
||||||
|
|
||||||
private var url: URL
|
private var url: URL
|
||||||
private var inputStream: InputStream?
|
private var inputStream: InputStream?
|
||||||
private var outputStream: OutputStream?
|
private var outputStream: OutputStream?
|
||||||
private var connected = false
|
private var connected = false
|
||||||
private var isConnecting = false
|
private var isConnecting = false
|
||||||
|
private var compressionState = CompressionState()
|
||||||
private var writeQueue = OperationQueue()
|
private var writeQueue = OperationQueue()
|
||||||
private var readStack = [WSResponse]()
|
private var readStack = [WSResponse]()
|
||||||
private var inputQueue = [Data]()
|
private var inputQueue = [Data]()
|
||||||
@ -147,6 +204,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
private var certValidated = false
|
private var certValidated = false
|
||||||
private var didDisconnect = false
|
private var didDisconnect = false
|
||||||
private var readyToWrite = false
|
private var readyToWrite = false
|
||||||
|
private var headerSecKey = ""
|
||||||
private let mutex = NSLock()
|
private let mutex = NSLock()
|
||||||
private let notificationCenter = NotificationCenter.default
|
private let notificationCenter = NotificationCenter.default
|
||||||
private var canDispatch: Bool {
|
private var canDispatch: Bool {
|
||||||
@ -246,7 +304,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
Private method that starts the connection.
|
Private method that starts the connection.
|
||||||
*/
|
*/
|
||||||
private func createHTTPRequest() {
|
private func createHTTPRequest() {
|
||||||
let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET" as CFString,
|
let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, httpMethod.representation as CFString,
|
||||||
url as CFURL, kCFHTTPVersion1_1).takeRetainedValue()
|
url as CFURL, kCFHTTPVersion1_1).takeRetainedValue()
|
||||||
|
|
||||||
var port = url.port
|
var port = url.port
|
||||||
@ -262,11 +320,16 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
if let protocols = optionalProtocols {
|
if let protocols = optionalProtocols {
|
||||||
addHeader(urlRequest, key: headerWSProtocolName, val: protocols.joined(separator: ","))
|
addHeader(urlRequest, key: headerWSProtocolName, val: protocols.joined(separator: ","))
|
||||||
}
|
}
|
||||||
|
headerSecKey = generateWebSocketKey()
|
||||||
addHeader(urlRequest, key: headerWSVersionName, val: headerWSVersionValue)
|
addHeader(urlRequest, key: headerWSVersionName, val: headerWSVersionValue)
|
||||||
addHeader(urlRequest, key: headerWSKeyName, val: generateWebSocketKey())
|
addHeader(urlRequest, key: headerWSKeyName, val: headerSecKey)
|
||||||
if let origin = origin {
|
if let origin = origin {
|
||||||
addHeader(urlRequest, key: headerOriginName, val: origin)
|
addHeader(urlRequest, key: headerOriginName, val: origin)
|
||||||
}
|
}
|
||||||
|
if enableCompression {
|
||||||
|
let val = "permessage-deflate; client_max_window_bits; server_max_window_bits=15"
|
||||||
|
addHeader(urlRequest, key: headerWSExtensionName, val: val)
|
||||||
|
}
|
||||||
addHeader(urlRequest, key: headerWSHostName, val: "\(url.host!):\(port!)")
|
addHeader(urlRequest, key: headerWSHostName, val: "\(url.host!):\(port!)")
|
||||||
for (key, value) in headers {
|
for (key, value) in headers {
|
||||||
addHeader(urlRequest, key: key, val: value)
|
addHeader(urlRequest, key: key, val: value)
|
||||||
@ -274,6 +337,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
if let cfHTTPMessage = CFHTTPMessageCopySerializedMessage(urlRequest) {
|
if let cfHTTPMessage = CFHTTPMessageCopySerializedMessage(urlRequest) {
|
||||||
let serializedRequest = cfHTTPMessage.takeRetainedValue()
|
let serializedRequest = cfHTTPMessage.takeRetainedValue()
|
||||||
initStreamsWithData(serializedRequest as Data, Int(port!))
|
initStreamsWithData(serializedRequest as Data, Int(port!))
|
||||||
|
self.advancedDelegate?.websocketHttpUpgrade(socket: self, request: urlRequest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,10 +410,6 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
} else {
|
} else {
|
||||||
certValidated = true //not a https session, so no need to check SSL pinning
|
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)
|
CFReadStreamSetDispatchQueue(inStream, WebSocket.sharedWorkQueue)
|
||||||
CFWriteStreamSetDispatchQueue(outStream, WebSocket.sharedWorkQueue)
|
CFWriteStreamSetDispatchQueue(outStream, WebSocket.sharedWorkQueue)
|
||||||
@ -373,7 +433,8 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
WebSocket.sharedWorkQueue.async {
|
WebSocket.sharedWorkQueue.async {
|
||||||
self?.cleanupStream()
|
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
|
return
|
||||||
} else if outStream.streamError != nil {
|
} else if outStream.streamError != nil {
|
||||||
return // disconnectStream will be called.
|
return // disconnectStream will be called.
|
||||||
@ -382,12 +443,16 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
guard !sOperation.isCancelled, let s = self else { return }
|
guard !sOperation.isCancelled, let s = self else { return }
|
||||||
// Do the pinning now if needed
|
// Do the pinning now if needed
|
||||||
if let sec = s.security, !s.certValidated {
|
if let sec = s.security, !s.certValidated {
|
||||||
let trust = outStream.property(forKey: kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) as! SecTrust
|
if let possibleTrust = outStream.property(forKey: kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) {
|
||||||
let domain = outStream.property(forKey: kCFStreamSSLPeerName as Stream.PropertyKey) as? String
|
let domain = outStream.property(forKey: kCFStreamSSLPeerName as Stream.PropertyKey) as? String
|
||||||
s.certValidated = sec.isValid(trust, domain: domain)
|
s.certValidated = sec.isValid(possibleTrust as! SecTrust, domain: domain)
|
||||||
|
} else {
|
||||||
|
s.certValidated = false
|
||||||
|
}
|
||||||
if !s.certValidated {
|
if !s.certValidated {
|
||||||
WebSocket.sharedWorkQueue.async {
|
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)
|
s.disconnectStream(error)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -539,6 +604,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
guard let s = self else { return }
|
guard let s = self else { return }
|
||||||
s.onConnect?()
|
s.onConnect?()
|
||||||
s.delegate?.websocketDidConnect(socket: s)
|
s.delegate?.websocketDidConnect(socket: s)
|
||||||
|
s.advancedDelegate?.websocketDidConnect(socket: s)
|
||||||
s.notificationCenter.post(name: NSNotification.Name(WebsocketDidConnectNotification), object: self)
|
s.notificationCenter.post(name: NSNotification.Name(WebsocketDidConnectNotification), object: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -559,13 +625,24 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue()
|
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue()
|
||||||
CFHTTPMessageAppendBytes(response, buffer, bufferLen)
|
CFHTTPMessageAppendBytes(response, buffer, bufferLen)
|
||||||
let code = CFHTTPMessageGetResponseStatusCode(response)
|
let code = CFHTTPMessageGetResponseStatusCode(response)
|
||||||
|
self.advancedDelegate?.websocketHttpUpgrade(socket: self, response: response)
|
||||||
if code != httpSwitchProtocolCode {
|
if code != httpSwitchProtocolCode {
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
if let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response) {
|
if let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response) {
|
||||||
let headers = cfHeaders.takeRetainedValue() as NSDictionary
|
let headers = cfHeaders.takeRetainedValue() as NSDictionary
|
||||||
|
if let extensionHeader = headers[headerWSExtensionName as NSString] as? String {
|
||||||
|
processExtensionHeader(extensionHeader)
|
||||||
|
}
|
||||||
|
|
||||||
if let acceptKey = headers[headerWSAcceptName as NSString] as? NSString {
|
if let acceptKey = headers[headerWSAcceptName as NSString] as? NSString {
|
||||||
if acceptKey.length > 0 {
|
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
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -573,6 +650,37 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Parses the extension header, setting up the compression parameters.
|
||||||
|
*/
|
||||||
|
func processExtensionHeader(_ extensionHeader: String) {
|
||||||
|
let parts = extensionHeader.components(separatedBy: ";")
|
||||||
|
for p in parts {
|
||||||
|
let part = p.trimmingCharacters(in: .whitespaces)
|
||||||
|
if part == "permessage-deflate" {
|
||||||
|
compressionState.supportsCompression = true
|
||||||
|
} 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=") {
|
||||||
|
let valString = part.components(separatedBy: "=")[1]
|
||||||
|
if let val = Int(valString.trimmingCharacters(in: .whitespaces)) {
|
||||||
|
compressionState.clientMaxWindowBits = val
|
||||||
|
}
|
||||||
|
} else if part == "client_no_context_takeover" {
|
||||||
|
compressionState.clientNoContextTakeover = true
|
||||||
|
} else if part == "server_no_context_takeover" {
|
||||||
|
compressionState.serverNoContextTakeover = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if compressionState.supportsCompression {
|
||||||
|
compressionState.decompressor = Decompressor(windowBits: compressionState.serverMaxWindowBits)
|
||||||
|
compressionState.compressor = Compressor(windowBits: compressionState.clientMaxWindowBits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Read a 16 bit big endian value from a buffer
|
Read a 16 bit big endian value from a buffer
|
||||||
*/
|
*/
|
||||||
@ -637,7 +745,10 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
let isMasked = (MaskMask & baseAddress[1])
|
let isMasked = (MaskMask & baseAddress[1])
|
||||||
let payloadLen = (PayloadLenMask & baseAddress[1])
|
let payloadLen = (PayloadLenMask & baseAddress[1])
|
||||||
var offset = 2
|
var offset = 2
|
||||||
if (isMasked > 0 || (RSVMask & baseAddress[0]) > 0) && receivedOpcode != .pong {
|
if compressionState.supportsCompression && receivedOpcode != .continueFrame {
|
||||||
|
compressionState.messageNeedsDecompression = (RSV1Mask & baseAddress[0]) > 0
|
||||||
|
}
|
||||||
|
if (isMasked > 0 || (RSVMask & baseAddress[0]) > 0) && receivedOpcode != .pong && !compressionState.messageNeedsDecompression {
|
||||||
let errCode = CloseCode.protocolError.rawValue
|
let errCode = CloseCode.protocolError.rawValue
|
||||||
doDisconnect(errorWithDetail("masked and rsv data is not currently supported", code: errCode))
|
doDisconnect(errorWithDetail("masked and rsv data is not currently supported", code: errCode))
|
||||||
writeError(errCode)
|
writeError(errCode)
|
||||||
@ -697,7 +808,23 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
offset += size
|
offset += size
|
||||||
len -= UInt64(size)
|
len -= UInt64(size)
|
||||||
}
|
}
|
||||||
let data = Data(bytes: baseAddress+offset, count: Int(len))
|
let data: Data
|
||||||
|
if compressionState.messageNeedsDecompression, let decompressor = compressionState.decompressor {
|
||||||
|
do {
|
||||||
|
data = try decompressor.decompress(bytes: baseAddress+offset, count: Int(len), finish: isFin > 0)
|
||||||
|
if isFin > 0 && compressionState.serverNoContextTakeover{
|
||||||
|
try decompressor.reset()
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
let closeReason = "Decompression failed: \(error)"
|
||||||
|
let closeCode = CloseCode.encoding.rawValue
|
||||||
|
doDisconnect(errorWithDetail(closeReason, code: closeCode))
|
||||||
|
writeError(closeCode)
|
||||||
|
return emptyBuffer
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = Data(bytes: baseAddress+offset, count: Int(len))
|
||||||
|
}
|
||||||
|
|
||||||
if receivedOpcode == .connectionClose {
|
if receivedOpcode == .connectionClose {
|
||||||
var closeReason = "connection closed by server"
|
var closeReason = "connection closed by server"
|
||||||
@ -804,6 +931,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
guard let s = self else { return }
|
guard let s = self else { return }
|
||||||
s.onText?(str! as String)
|
s.onText?(str! as String)
|
||||||
s.delegate?.websocketDidReceiveMessage(socket: s, text: str! as String)
|
s.delegate?.websocketDidReceiveMessage(socket: s, text: str! as String)
|
||||||
|
s.advancedDelegate?.websocketDidReceiveMessage(socket: s, text: str! as String, response: response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if response.code == .binaryFrame {
|
} else if response.code == .binaryFrame {
|
||||||
@ -813,6 +941,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
guard let s = self else { return }
|
guard let s = self else { return }
|
||||||
s.onData?(data as Data)
|
s.onData?(data as Data)
|
||||||
s.delegate?.websocketDidReceiveData(socket: s, data: data as Data)
|
s.delegate?.websocketDidReceiveData(socket: s, data: data as Data)
|
||||||
|
s.advancedDelegate?.websocketDidReceiveData(socket: s, data: data as Data, response: response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -851,10 +980,23 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
guard let s = self else { return }
|
guard let s = self else { return }
|
||||||
guard let sOperation = operation else { return }
|
guard let sOperation = operation else { return }
|
||||||
var offset = 2
|
var offset = 2
|
||||||
|
var firstByte:UInt8 = s.FinMask | code.rawValue
|
||||||
|
var data = data
|
||||||
|
if [.textFrame, .binaryFrame].contains(code), let compressor = s.compressionState.compressor {
|
||||||
|
do {
|
||||||
|
data = try compressor.compress(data)
|
||||||
|
if s.compressionState.clientNoContextTakeover {
|
||||||
|
try compressor.reset()
|
||||||
|
}
|
||||||
|
firstByte |= s.RSV1Mask
|
||||||
|
} catch {
|
||||||
|
// TODO: report error? We can just send the uncompressed frame.
|
||||||
|
}
|
||||||
|
}
|
||||||
let dataLength = data.count
|
let dataLength = data.count
|
||||||
let frame = NSMutableData(capacity: dataLength + s.MaxFrameSize)
|
let frame = NSMutableData(capacity: dataLength + s.MaxFrameSize)
|
||||||
let buffer = UnsafeMutableRawPointer(frame!.mutableBytes).assumingMemoryBound(to: UInt8.self)
|
let buffer = UnsafeMutableRawPointer(frame!.mutableBytes).assumingMemoryBound(to: UInt8.self)
|
||||||
buffer[0] = s.FinMask | code.rawValue
|
buffer[0] = firstByte
|
||||||
if dataLength < 126 {
|
if dataLength < 126 {
|
||||||
buffer[1] = CUnsignedChar(dataLength)
|
buffer[1] = CUnsignedChar(dataLength)
|
||||||
} else if dataLength <= Int(UInt16.max) {
|
} else if dataLength <= Int(UInt16.max) {
|
||||||
@ -920,6 +1062,7 @@ open class WebSocket : NSObject, StreamDelegate {
|
|||||||
guard let s = self else { return }
|
guard let s = self else { return }
|
||||||
s.onDisconnect?(error)
|
s.onDisconnect?(error)
|
||||||
s.delegate?.websocketDidDisconnect(socket: s, error: error)
|
s.delegate?.websocketDidDisconnect(socket: s, error: error)
|
||||||
|
s.advancedDelegate?.websocketDidDisconnect(socket: s, error: error)
|
||||||
let userInfo = error.map{ [WebsocketDisconnectionErrorKeyName: $0] }
|
let userInfo = error.map{ [WebsocketDisconnectionErrorKeyName: $0] }
|
||||||
s.notificationCenter.post(name: NSNotification.Name(WebsocketDidDisconnectNotification), object: self, userInfo: userInfo)
|
s.notificationCenter.post(name: NSNotification.Name(WebsocketDidDisconnectNotification), object: self, userInfo: userInfo)
|
||||||
}
|
}
|
||||||
@ -936,6 +1079,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 {
|
private extension Data {
|
||||||
|
|
||||||
init(buffer: UnsafeBufferPointer<UInt8>) {
|
init(buffer: UnsafeBufferPointer<UInt8>) {
|
||||||
|
|||||||
2
zlib/include.h
Normal file
2
zlib/include.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include <zlib.h>
|
||||||
|
#include <CommonCrypto/CommonCrypto.h>
|
||||||
8
zlib/module.modulemap
Normal file
8
zlib/module.modulemap
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module zlib [system] {
|
||||||
|
header "include.h"
|
||||||
|
link "z"
|
||||||
|
}
|
||||||
|
module CommonCrypto [system] {
|
||||||
|
header "include.h"
|
||||||
|
export *
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user