From d1cbbc02131a85ab20eab7897ccdc43628d1127d Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 2 Jul 2017 11:31:30 -0400 Subject: [PATCH 1/7] Update websocket --- Source/Compression.swift | 174 +++++++++++++++++++++++++++++++++++++++ zlib/include.h | 2 + zlib/module.modulemap | 8 ++ 3 files changed, 184 insertions(+) create mode 100644 Source/Compression.swift create mode 100644 zlib/include.h create mode 100644 zlib/module.modulemap diff --git a/Source/Compression.swift b/Source/Compression.swift new file mode 100644 index 0000000..bc4b29f --- /dev/null +++ b/Source/Compression.swift @@ -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.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) -> Data in + return try decompress(bytes: bytes, count: data.count, finish: finish) + } + } + + func decompress(bytes: UnsafePointer, 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, count: Int, out:inout Data) throws { + var res:CInt = 0 + strm.next_in = UnsafeMutablePointer(mutating: bytes) + strm.avail_in = CUnsignedInt(count) + + repeat { + strm.next_out = UnsafeMutablePointer(&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.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) -> Void in + strm.next_in = UnsafeMutablePointer(mutating: ptr) + strm.avail_in = CUnsignedInt(data.count) + + repeat { + strm.next_out = UnsafeMutablePointer(&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() + } +} diff --git a/zlib/include.h b/zlib/include.h new file mode 100644 index 0000000..cb3747f --- /dev/null +++ b/zlib/include.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/zlib/module.modulemap b/zlib/module.modulemap new file mode 100644 index 0000000..7172f84 --- /dev/null +++ b/zlib/module.modulemap @@ -0,0 +1,8 @@ +module zlib [system] { + header "include.h" + link "z" +} +module CommonCrypto [system] { + header "include.h" + export * +} From c6dd1fb19b91b7a219b02619561eb7e419b0e304 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 2 Jul 2017 11:32:56 -0400 Subject: [PATCH 2/7] add missing updates --- Package.swift | 6 +- Socket.IO-Client-Swift.podspec | 1 + .../project.pbxproj | 64 ++++++ Source/SocketEngine.swift | 1 - Source/WebSocket.swift | 194 ++++++++++++++++-- 5 files changed, 243 insertions(+), 23 deletions(-) diff --git a/Package.swift b/Package.swift index 04e8fbb..9102d4e 100644 --- a/Package.swift +++ b/Package.swift @@ -1,5 +1,9 @@ import PackageDescription 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) + ] ) diff --git a/Socket.IO-Client-Swift.podspec b/Socket.IO-Client-Swift.podspec index 88e2b10..35216fd 100644 --- a/Socket.IO-Client-Swift.podspec +++ b/Socket.IO-Client-Swift.podspec @@ -18,5 +18,6 @@ Pod::Spec.new do |s| s.source_files = "Source/**/*.swift" s.requires_arc = true s.pod_target_xcconfig = {'SWIFT_VERSION' => '3.1'} + s.libraries = 'z' # s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files end diff --git a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj index de5755c..5ec5af5 100644 --- a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj +++ b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj @@ -99,6 +99,16 @@ 74BC45AB1D0C6675008CC431 /* 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 */; }; + 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 */; }; 74F124F11BC574CF002966F4 /* SocketBasicPacketTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74F124EF1BC574CF002966F4 /* SocketBasicPacketTest.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 = ""; }; 74ABF7761C3991C10078C657 /* SocketIOClientSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketIOClientSpec.swift; path = Source/SocketIOClientSpec.swift; sourceTree = ""; }; 74BC45AA1D0C6675008CC431 /* SocketClientManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketClientManager.swift; path = Source/SocketClientManager.swift; sourceTree = ""; }; + 74DA216C1F09438D009C19EE /* include.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = include.h; path = zlib/include.h; sourceTree = ""; }; + 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 = ""; }; + 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 = ""; }; 74F124EF1BC574CF002966F4 /* SocketBasicPacketTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketBasicPacketTest.swift; sourceTree = ""; }; CEBA56991CDA0B8200BA0389 /* SocketExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketExtensions.swift; path = Source/SocketExtensions.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -184,6 +201,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 74DA21721F094408009C19EE /* libz.tbd in Frameworks */, 6CA08A961D615C040061FD2A /* Security.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -200,6 +218,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 74DA21741F09440F009C19EE /* libz.tbd in Frameworks */, 6CA08A981D615C0B0061FD2A /* Security.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -208,6 +227,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 74DA217C1F09457B009C19EE /* libz.tbd in Frameworks */, 572EF2431B51F18A00EEBB58 /* SocketIO.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -216,6 +236,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 74DA21761F094417009C19EE /* libz.tbd in Frameworks */, 6CA08A9A1D615C140061FD2A /* Security.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -234,6 +255,7 @@ 572EF20D1B51F12F00EEBB58 = { isa = PBXGroup; children = ( + 74DA216B1F094371009C19EE /* zlib */, 6CA08A9B1D615C190061FD2A /* Frameworks */, 572EF21A1B51F16C00EEBB58 /* Products */, 572EF21B1B51F16C00EEBB58 /* SocketIO-iOS */, @@ -347,6 +369,10 @@ 6CA08A9B1D615C190061FD2A /* Frameworks */ = { isa = PBXGroup; children = ( + 74DA217D1F0945E9009C19EE /* libcommonCrypto.tbd */, + 74DA21751F094417009C19EE /* libz.tbd */, + 74DA21731F09440F009C19EE /* libz.tbd */, + 74DA21711F094408009C19EE /* libz.tbd */, 6CA08A9E1D615C340061FD2A /* tvOS */, 6CA08A9D1D615C2C0061FD2A /* Mac */, 6CA08A9C1D615C270061FD2A /* iOS */, @@ -381,12 +407,22 @@ 74B4AD1B1D09A5C30062A523 /* Websocket */ = { isa = PBXGroup; children = ( + 74DA21801F094887009C19EE /* Compression.swift */, 749642B31D3FCE5500DD32D1 /* SSLSecurity.swift */, 749642B41D3FCE5500DD32D1 /* WebSocket.swift */, ); name = Websocket; sourceTree = ""; }; + 74DA216B1F094371009C19EE /* zlib */ = { + isa = PBXGroup; + children = ( + 74DA216C1F09438D009C19EE /* include.h */, + 74DA21771F09444E009C19EE /* module.modulemap */, + ); + name = zlib; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -395,6 +431,7 @@ buildActionMask = 2147483647; files = ( 572EF21F1B51F16C00EEBB58 /* SocketIO.h in Headers */, + 74DA21701F0943F8009C19EE /* include.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -403,6 +440,7 @@ buildActionMask = 2147483647; files = ( 572EF23D1B51F18A00EEBB58 /* SocketIO-Mac.h in Headers */, + 74DA216F1F0943F4009C19EE /* include.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -411,6 +449,7 @@ buildActionMask = 2147483647; files = ( 57634A111BD9B46A00E19CD7 /* SocketIO.h in Headers */, + 74DA216E1F0943EE009C19EE /* include.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -643,6 +682,7 @@ 749642B51D3FCE5500DD32D1 /* SSLSecurity.swift in Sources */, 74171EB71C10CD240062D398 /* SocketParsable.swift in Sources */, 74171E811C10CD240062D398 /* SocketEnginePacketType.swift in Sources */, + 74DA21811F094887009C19EE /* Compression.swift in Sources */, 74171E6F1C10CD240062D398 /* SocketAnyEvent.swift in Sources */, 747BC5991D5F943500CA5FA4 /* SocketIOClientConfiguration.swift in Sources */, 74171E9F1C10CD240062D398 /* SocketIOClientOption.swift in Sources */, @@ -685,6 +725,7 @@ 749642B61D3FCE5500DD32D1 /* SSLSecurity.swift in Sources */, 74171EB91C10CD240062D398 /* SocketParsable.swift in Sources */, 74171E831C10CD240062D398 /* SocketEnginePacketType.swift in Sources */, + 74DA21821F094887009C19EE /* Compression.swift in Sources */, 74171E711C10CD240062D398 /* SocketAnyEvent.swift in Sources */, 747BC59A1D5F943500CA5FA4 /* SocketIOClientConfiguration.swift in Sources */, 74171EA11C10CD240062D398 /* SocketIOClientOption.swift in Sources */, @@ -731,6 +772,7 @@ 749642B71D3FCE5500DD32D1 /* SSLSecurity.swift in Sources */, 74171EBB1C10CD240062D398 /* SocketParsable.swift in Sources */, 74171E851C10CD240062D398 /* SocketEnginePacketType.swift in Sources */, + 74DA21831F094887009C19EE /* Compression.swift in Sources */, 74171E731C10CD240062D398 /* SocketAnyEvent.swift in Sources */, 747BC59B1D5F943500CA5FA4 /* SocketIOClientConfiguration.swift in Sources */, 74171EA31C10CD240062D398 /* SocketIOClientOption.swift in Sources */, @@ -885,6 +927,7 @@ PRODUCT_BUNDLE_IDENTIFIER = io.socket.SocketIOClientSwift; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SWIFT_INCLUDE_PATHS = $SRCROOT/zlib; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -937,6 +980,7 @@ PRODUCT_BUNDLE_IDENTIFIER = io.socket.SocketIOClientSwift; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SWIFT_INCLUDE_PATHS = $SRCROOT/zlib; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; @@ -1088,11 +1132,16 @@ INFOPLIST_FILE = "SocketIO-Mac/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/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; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)"; SDKROOT = macosx; SKIP_INSTALL = YES; + SWIFT_INCLUDE_PATHS = $SRCROOT/zlib; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 3.0; VERSIONING_SYSTEM = "apple-generic"; @@ -1142,10 +1191,15 @@ INFOPLIST_FILE = "SocketIO-Mac/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/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; PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)"; SDKROOT = macosx; SKIP_INSTALL = YES; + SWIFT_INCLUDE_PATHS = $SRCROOT/zlib; SWIFT_VERSION = 3.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -1196,6 +1250,10 @@ GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = "SocketIO-MacTests/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)/usr/lib/system", + ); MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; @@ -1245,6 +1303,10 @@ GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = "SocketIO-MacTests/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)/usr/lib/system", + ); MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "io.socket.$(PRODUCT_NAME:rfc1034identifier)"; @@ -1304,6 +1366,7 @@ PRODUCT_NAME = SocketIO; SDKROOT = appletvos; SKIP_INSTALL = YES; + SWIFT_INCLUDE_PATHS = $SRCROOT/zlib; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; @@ -1356,6 +1419,7 @@ PRODUCT_NAME = SocketIO; SDKROOT = appletvos; SKIP_INSTALL = YES; + SWIFT_INCLUDE_PATHS = $SRCROOT/zlib; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index 5c1f841..fc43ea3 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -331,7 +331,6 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll } ws?.callbackQueue = engineQueue - ws?.voipEnabled = voipEnabled ws?.delegate = self ws?.disableSSLCertValidation = selfSigned ws?.security = security diff --git a/Source/WebSocket.swift b/Source/WebSocket.swift index f57ec3d..38a25bd 100644 --- a/Source/WebSocket.swift +++ b/Source/WebSocket.swift @@ -20,7 +20,7 @@ ////////////////////////////////////////////////////////////////////////////////////////////////// import Foundation import CoreFoundation -import Security +import CommonCrypto public let WebsocketDidConnectNotification = "WebsocketDidConnectNotification" public let WebsocketDidDisconnectNotification = "WebsocketDidDisconnectNotification" @@ -37,9 +37,19 @@ public protocol WebSocketPongDelegate: class { 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 { - enum OpCode : UInt8 { + public enum OpCode : UInt8 { case continueFrame = 0x0 case textFrame = 0x1 case binaryFrame = 0x2 @@ -68,6 +78,9 @@ open class WebSocket : NSObject, StreamDelegate { enum InternalErrorCode: UInt16 { // 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. @@ -84,6 +97,7 @@ open class WebSocket : NSObject, StreamDelegate { let headerWSProtocolName = "Sec-WebSocket-Protocol" let headerWSVersionName = "Sec-WebSocket-Version" let headerWSVersionValue = "13" + let headerWSExtensionName = "Sec-WebSocket-Extensions" let headerWSKeyName = "Sec-WebSocket-Key" let headerOriginName = "Origin" let headerWSAcceptName = "Sec-WebSocket-Accept" @@ -91,18 +105,22 @@ open class WebSocket : NSObject, StreamDelegate { let FinMask: UInt8 = 0x80 let OpCodeMask: UInt8 = 0x0F let RSVMask: UInt8 = 0x70 + let RSV1Mask: UInt8 = 0x40 let MaskMask: UInt8 = 0x80 let PayloadLenMask: UInt8 = 0x7F let MaxFrameSize: Int = 32 let httpSwitchProtocolCode = 101 let supportedSSLSchemes = ["wss", "https"] - class WSResponse { + public class WSResponse { var isFin = false - var code: OpCode = .continueFrame + public var code: OpCode = .continueFrame var bytesLeft = 0 - var frameCount = 0 - var buffer: NSMutableData? + public var frameCount = 0 + public var buffer: NSMutableData? + public let firstFrame = { + return Date() + }() } // MARK: - Delegates @@ -110,20 +128,46 @@ open class WebSocket : NSObject, StreamDelegate { /// and also connection/disconnect messages. 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. public weak var pongDelegate: WebSocketPongDelegate? // 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 onDisconnect: ((NSError?) -> Void)? public var onText: ((String) -> Void)? public var onData: ((Data) -> Void)? public var onPong: ((Data?) -> Void)? + 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? public var enabledSSLCipherSuites: [SSLCipherSuite]? public var origin: String? @@ -135,11 +179,24 @@ open class WebSocket : NSObject, StreamDelegate { public var currentURL: URL { return url } // 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 inputStream: InputStream? private var outputStream: OutputStream? private var connected = false private var isConnecting = false + private var compressionState = CompressionState() private var writeQueue = OperationQueue() private var readStack = [WSResponse]() private var inputQueue = [Data]() @@ -147,6 +204,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 { @@ -246,7 +304,7 @@ open class WebSocket : NSObject, StreamDelegate { Private method that starts the connection. */ private func createHTTPRequest() { - let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET" as CFString, + let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, httpMethod.representation as CFString, url as CFURL, kCFHTTPVersion1_1).takeRetainedValue() var port = url.port @@ -262,11 +320,16 @@ 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) } + 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!)") for (key, value) in headers { addHeader(urlRequest, key: key, val: value) @@ -274,6 +337,7 @@ open class WebSocket : NSObject, StreamDelegate { if let cfHTTPMessage = CFHTTPMessageCopySerializedMessage(urlRequest) { let serializedRequest = cfHTTPMessage.takeRetainedValue() initStreamsWithData(serializedRequest as Data, Int(port!)) + self.advancedDelegate?.websocketHttpUpgrade(socket: self, request: urlRequest) } } @@ -346,10 +410,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) @@ -373,7 +433,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. @@ -382,12 +443,16 @@ open class WebSocket : NSObject, StreamDelegate { guard !sOperation.isCancelled, let s = self else { return } // Do the pinning now if needed if let sec = s.security, !s.certValidated { - let trust = outStream.property(forKey: kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) as! SecTrust - let domain = outStream.property(forKey: kCFStreamSSLPeerName as Stream.PropertyKey) as? String - s.certValidated = sec.isValid(trust, domain: domain) + if let possibleTrust = outStream.property(forKey: kCFStreamPropertySSLPeerTrust as Stream.PropertyKey) { + let domain = outStream.property(forKey: kCFStreamSSLPeerName as Stream.PropertyKey) as? String + s.certValidated = sec.isValid(possibleTrust as! SecTrust, domain: domain) + } else { + s.certValidated = false + } 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 @@ -539,6 +604,7 @@ open class WebSocket : NSObject, StreamDelegate { guard let s = self else { return } s.onConnect?() s.delegate?.websocketDidConnect(socket: s) + s.advancedDelegate?.websocketDidConnect(socket: s) s.notificationCenter.post(name: NSNotification.Name(WebsocketDidConnectNotification), object: self) } } @@ -559,13 +625,24 @@ open class WebSocket : NSObject, StreamDelegate { let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue() CFHTTPMessageAppendBytes(response, buffer, bufferLen) let code = CFHTTPMessageGetResponseStatusCode(response) + self.advancedDelegate?.websocketHttpUpgrade(socket: self, response: response) if code != httpSwitchProtocolCode { return code } if let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response) { 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 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 } } @@ -573,6 +650,37 @@ open class WebSocket : NSObject, StreamDelegate { 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 */ @@ -637,7 +745,10 @@ open class WebSocket : NSObject, StreamDelegate { let isMasked = (MaskMask & baseAddress[1]) let payloadLen = (PayloadLenMask & baseAddress[1]) 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 doDisconnect(errorWithDetail("masked and rsv data is not currently supported", code: errCode)) writeError(errCode) @@ -697,7 +808,23 @@ open class WebSocket : NSObject, StreamDelegate { offset += 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 { var closeReason = "connection closed by server" @@ -804,6 +931,7 @@ open class WebSocket : NSObject, StreamDelegate { guard let s = self else { return } s.onText?(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 { @@ -813,6 +941,7 @@ open class WebSocket : NSObject, StreamDelegate { guard let s = self else { return } s.onData?(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 sOperation = operation else { return } 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 frame = NSMutableData(capacity: dataLength + s.MaxFrameSize) let buffer = UnsafeMutableRawPointer(frame!.mutableBytes).assumingMemoryBound(to: UInt8.self) - buffer[0] = s.FinMask | code.rawValue + buffer[0] = firstByte if dataLength < 126 { buffer[1] = CUnsignedChar(dataLength) } else if dataLength <= Int(UInt16.max) { @@ -920,6 +1062,7 @@ open class WebSocket : NSObject, StreamDelegate { guard let s = self else { return } s.onDisconnect?(error) s.delegate?.websocketDidDisconnect(socket: s, error: error) + s.advancedDelegate?.websocketDidDisconnect(socket: s, error: error) let userInfo = error.map{ [WebsocketDisconnectionErrorKeyName: $0] } 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 { init(buffer: UnsafeBufferPointer) { From 839987727e8d336a78d7dc956f78069365446aad Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 2 Jul 2017 12:25:02 -0400 Subject: [PATCH 3/7] Fix cocoapods --- Socket.IO-Client-Swift.podspec | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Socket.IO-Client-Swift.podspec b/Socket.IO-Client-Swift.podspec index 35216fd..4761197 100644 --- a/Socket.IO-Client-Swift.podspec +++ b/Socket.IO-Client-Swift.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Socket.IO-Client-Swift" 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.description = <<-DESC Socket.IO-client for iOS and OS X. @@ -14,10 +14,14 @@ 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 => '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.requires_arc = true - s.pod_target_xcconfig = {'SWIFT_VERSION' => '3.1'} s.libraries = 'z' + s.preserve_paths = 'zlib/*' + s.requires_arc = true + 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 end From 7ff10d141f5370b04972fb571952d5f3f3279167 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 2 Jul 2017 13:28:16 -0400 Subject: [PATCH 4/7] Add compress option --- Source/SocketEngine.swift | 6 ++++++ Source/SocketIOClientOption.swift | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index fc43ea3..da5e017 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -60,6 +60,9 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll /// `true` if this engine is closed. 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. public private(set) var connected = false @@ -171,6 +174,8 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll self.selfSigned = selfSigned case let .security(security): self.security = security + case .compress: + self.compress = true default: continue } @@ -331,6 +336,7 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll } ws?.callbackQueue = engineQueue + ws?.enableCompression = compress ws?.delegate = self ws?.disableSSLCertValidation = selfSigned ws?.security = security diff --git a/Source/SocketIOClientOption.swift b/Source/SocketIOClientOption.swift index f594b6b..6802fa0 100644 --- a/Source/SocketIOClientOption.swift +++ b/Source/SocketIOClientOption.swift @@ -30,6 +30,9 @@ protocol ClientOption : CustomStringConvertible, Equatable { /// The options for a client. 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. case connectParams([String: Any]) @@ -103,6 +106,8 @@ public enum SocketIOClientOption : ClientOption { let description: String switch self { + case .compress: + description = "compress" case .connectParams: description = "connectParams" case .cookies: @@ -152,6 +157,8 @@ public enum SocketIOClientOption : ClientOption { let value: Any switch self { + case .compress: + value = true case let .connectParams(params): value = params case let .cookies(cookies): From d37c7123d9282561bee1a2563fae470ffb7ba46c Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 2 Jul 2017 13:35:52 -0400 Subject: [PATCH 5/7] add note about voip --- Source/SocketIOClientOption.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/SocketIOClientOption.swift b/Source/SocketIOClientOption.swift index 6802fa0..9ab5cc7 100644 --- a/Source/SocketIOClientOption.swift +++ b/Source/SocketIOClientOption.swift @@ -97,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 /// 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) // MARK: Properties From a2ea2df83a25e83407344c57bc406d2df0f89689 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 2 Jul 2017 13:43:01 -0400 Subject: [PATCH 6/7] Add compress to NSDictionary to option method --- Source/SocketEngine.swift | 3 --- Source/SocketExtensions.swift | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index da5e017..6d7ae5e 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -134,7 +134,6 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll private var secure = false private var security: SSLSecurity? private var selfSigned = false - private var voipEnabled = false // MARK: Initializers @@ -166,8 +165,6 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll if !socketPath.hasSuffix("/") { socketPath += "/" } - case let .voipEnabled(enable): - voipEnabled = enable case let .secure(secure): self.secure = secure case let .selfSigned(selfSigned): diff --git a/Source/SocketExtensions.swift b/Source/SocketExtensions.swift index 94aca5f..fc15ad5 100644 --- a/Source/SocketExtensions.swift +++ b/Source/SocketExtensions.swift @@ -80,8 +80,8 @@ extension NSDictionary { return .selfSigned(selfSigned) case let ("sessionDelegate", delegate as URLSessionDelegate): return .sessionDelegate(delegate) - case let ("voipEnabled", enable as Bool): - return .voipEnabled(enable) + case let ("compress", compress as Bool): + return compress ? .compress : nil default: return nil } From 8f22bdef46ba3413362100336220d43e5a3ee89e Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 2 Jul 2017 13:44:58 -0400 Subject: [PATCH 7/7] update readme --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 62172be..a58418e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Socket.IO-client for iOS/OS X. ```swift 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 print("socket connected") @@ -30,7 +30,7 @@ socket.connect() ```objective-c @import SocketIO; 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) { NSLog(@"socket connected"); @@ -92,7 +92,7 @@ Then import `import SocketIO`. ### Carthage 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`. @@ -104,7 +104,7 @@ Create `Podfile` and add `pod 'Socket.IO-Client-Swift'`: use_frameworks! 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 ``` @@ -132,7 +132,7 @@ Objective-C: 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`.