diff --git a/SocketIO-MacTests/SocketEngineTest.swift b/SocketIO-MacTests/SocketEngineTest.swift index b797e04..c8cc46d 100644 --- a/SocketIO-MacTests/SocketEngineTest.swift +++ b/SocketIO-MacTests/SocketEngineTest.swift @@ -17,28 +17,28 @@ class SocketEngineTest: XCTestCase { super.setUp() client = SocketIOClient(socketURL: URL(string: "http://localhost")!) engine = SocketEngine(client: client, url: URL(string: "http://localhost")!, options: nil) - + client.setTestable() } - + func testBasicPollingMessage() { let expect = expectation(description: "Basic polling test") client.on("blankTest") {data, ack in expect.fulfill() } - + engine.parsePollingMessage("15:42[\"blankTest\"]") waitForExpectations(timeout: 3, handler: nil) } - + func testTwoPacketsInOnePollTest() { let finalExpectation = expectation(description: "Final packet in poll test") var gotBlank = false - + client.on("blankTest") {data, ack in gotBlank = true } - + client.on("stringTest") {data, ack in if let str = data[0] as? String, gotBlank { if str == "hello" { @@ -46,44 +46,46 @@ class SocketEngineTest: XCTestCase { } } } - + engine.parsePollingMessage("15:42[\"blankTest\"]24:42[\"stringTest\",\"hello\"]") waitForExpectations(timeout: 3, handler: nil) } - + func testEngineDoesErrorOnUnknownTransport() { let finalExpectation = expectation(description: "Unknown Transport") - + client.on("error") {data, ack in if let error = data[0] as? String, error == "Unknown transport" { finalExpectation.fulfill() } } - - engine.parseEngineMessage("{\"code\": 0, \"message\": \"Unknown transport\"}", fromPolling: false) + + engine.parseEngineMessage("{\"code\": 0, \"message\": \"Unknown transport\"}") waitForExpectations(timeout: 3, handler: nil) } - + func testEngineDoesErrorOnUnknownMessage() { let finalExpectation = expectation(description: "Engine Errors") - + client.on("error") {data, ack in finalExpectation.fulfill() } - - engine.parseEngineMessage("afafafda", fromPolling: false) + + engine.parseEngineMessage("afafafda") waitForExpectations(timeout: 3, handler: nil) } - + func testEngineDecodesUTF8Properly() { let expect = expectation(description: "Engine Decodes utf8") - + client.on("stringTest") {data, ack in - XCTAssertEqual(data[0] as? String, "lïne one\nlīne \rtwo", "Failed string test") + XCTAssertEqual(data[0] as? String, "lïne one\nlīne \rtwo𦅙𦅛", "Failed string test") expect.fulfill() } - engine.parsePollingMessage("41:42[\"stringTest\",\"lïne one\\nlÄ«ne \\rtwo\"]") + let stringMessage = "42[\"stringTest\",\"lïne one\\nlīne \\rtwo𦅙𦅛\"]" + + engine.parsePollingMessage("\(stringMessage.utf16.count):\(stringMessage)") waitForExpectations(timeout: 3, handler: nil) } @@ -102,23 +104,23 @@ class SocketEngineTest: XCTestCase { XCTAssertEqual(engine.urlPolling.query, "transport=polling&b64=1&forbidden=%21%2A%27%28%29%3B%3A%40%26%3D%2B%24%2C%2F%3F%25%23%5B%5D%22%20%7B%7D") XCTAssertEqual(engine.urlWebSocket.query, "transport=websocket&forbidden=%21%2A%27%28%29%3B%3A%40%26%3D%2B%24%2C%2F%3F%25%23%5B%5D%22%20%7B%7D") } - + func testBase64Data() { let expect = expectation(description: "Engine Decodes base64 data") let b64String = "b4aGVsbG8NCg==" let packetString = "451-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0}}]" - + client.on("test") {data, ack in if let data = data[0] as? Data, let string = String(data: data, encoding: .utf8) { XCTAssertEqual(string, "hello") } - + expect.fulfill() } - - engine.parseEngineMessage(packetString, fromPolling: false) - engine.parseEngineMessage(b64String, fromPolling: false) - + + engine.parseEngineMessage(packetString) + engine.parseEngineMessage(b64String) + waitForExpectations(timeout: 3, handler: nil) } } diff --git a/Source/SocketEngine.swift b/Source/SocketEngine.swift index e3c8944..7f561bb 100644 --- a/Source/SocketEngine.swift +++ b/Source/SocketEngine.swift @@ -511,11 +511,10 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll /// - parameter message: The message to parse. /// - parameter fromPolling: Whether this message is from long-polling. /// If `true` we might have to fix utf8 encoding. - public func parseEngineMessage(_ message: String, fromPolling: Bool) { + public func parseEngineMessage(_ message: String) { DefaultSocketLogger.Logger.log("Got message: %@", type: logType, args: message) let reader = SocketStringReader(message: message) - let fixedString: String if message.hasPrefix("b4") { return handleBase64(message: message) @@ -527,23 +526,17 @@ public final class SocketEngine : NSObject, URLSessionDelegate, SocketEnginePoll return } - if fromPolling && type != .noop && doubleEncodeUTF8 { - fixedString = fixDoubleUTF8(message) - } else { - fixedString = message - } - switch type { case .message: - handleMessage(String(fixedString.characters.dropFirst())) + handleMessage(String(message.characters.dropFirst())) case .noop: handleNOOP() case .pong: - handlePong(with: fixedString) + handlePong(with: message) case .open: - handleOpen(openData: String(fixedString.characters.dropFirst())) + handleOpen(openData: String(message.characters.dropFirst())) case .close: - handleClose(fixedString) + handleClose(message) default: DefaultSocketLogger.Logger.log("Got unknown packet type", type: logType) } diff --git a/Source/SocketEnginePollable.swift b/Source/SocketEnginePollable.swift index 3c73927..43bfb68 100644 --- a/Source/SocketEnginePollable.swift +++ b/Source/SocketEnginePollable.swift @@ -90,9 +90,7 @@ extension SocketEnginePollable { var postStr = "" for packet in postWait { - let len = packet.characters.count - - postStr += "\(len):\(packet)" + postStr += "\(packet.utf16.count):\(packet)" } DefaultSocketLogger.Logger.log("Created POST string: %@", type: "SocketEnginePolling", args: postStr) @@ -202,13 +200,15 @@ extension SocketEnginePollable { func parsePollingMessage(_ str: String) { guard str.characters.count != 1 else { return } + DefaultSocketLogger.Logger.log("Got poll message: %@", type: "SocketEnginePolling", args: str) + var reader = SocketStringReader(message: str) while reader.hasNext { if let n = Int(reader.readUntilOccurence(of: ":")) { - parseEngineMessage(reader.read(count: n), fromPolling: true) + parseEngineMessage(reader.read(count: n)) } else { - parseEngineMessage(str, fromPolling: true) + parseEngineMessage(str) break } } @@ -223,15 +223,8 @@ extension SocketEnginePollable { /// - parameter withData: The data associated with this message. public func sendPollMessage(_ message: String, withType type: SocketEnginePacketType, withData datas: [Data]) { DefaultSocketLogger.Logger.log("Sending poll: %@ as type: %@", type: "SocketEnginePolling", args: message, type.rawValue) - let fixedMessage: String - if doubleEncodeUTF8 { - fixedMessage = doubleEncodeUTF8(message) - } else { - fixedMessage = message - } - - postWait.append(String(type.rawValue) + fixedMessage) + postWait.append(String(type.rawValue) + message) for data in datas { if case let .right(bin) = createBinaryDataForSend(using: data) { diff --git a/Source/SocketEngineSpec.swift b/Source/SocketEngineSpec.swift index a70d99d..07171ce 100644 --- a/Source/SocketEngineSpec.swift +++ b/Source/SocketEngineSpec.swift @@ -125,7 +125,7 @@ import Foundation /// - parameter message: The message to parse. /// - parameter fromPolling: Whether this message is from long-polling. /// If `true` we might have to fix utf8 encoding. - func parseEngineMessage(_ message: String, fromPolling: Bool) + func parseEngineMessage(_ message: String) /// Writes a message to engine.io, independent of transport. /// @@ -165,24 +165,6 @@ extension SocketEngineSpec { } } - func doubleEncodeUTF8(_ string: String) -> String { - if let latin1 = string.data(using: String.Encoding.utf8), - let utf8 = NSString(data: latin1, encoding: String.Encoding.isoLatin1.rawValue) { - return utf8 as String - } else { - return string - } - } - - func fixDoubleUTF8(_ string: String) -> String { - if let utf8 = string.data(using: String.Encoding.isoLatin1), - let latin1 = NSString(data: utf8, encoding: String.Encoding.utf8.rawValue) { - return latin1 as String - } else { - return string - } - } - /// Send an engine message (4) func send(_ msg: String, withData datas: [Data]) { write(msg, withType: .message, withData: datas) diff --git a/Source/SocketEngineWebsocket.swift b/Source/SocketEngineWebsocket.swift index 64265c4..3a76a9d 100644 --- a/Source/SocketEngineWebsocket.swift +++ b/Source/SocketEngineWebsocket.swift @@ -68,7 +68,7 @@ extension SocketEngineWebsocket { /// Delegate method for when a message is received. public func websocketDidReceiveMessage(socket: WebSocket, text: String) { - parseEngineMessage(text, fromPolling: false) + parseEngineMessage(text) } /// Delegate method for when binary is received. diff --git a/Source/SocketExtensions.swift b/Source/SocketExtensions.swift index bf5280a..cb1145e 100644 --- a/Source/SocketExtensions.swift +++ b/Source/SocketExtensions.swift @@ -88,39 +88,39 @@ extension NSDictionary { return nil } } - + func toSocketConfiguration() -> SocketIOClientConfiguration { var options = [] as SocketIOClientConfiguration - + for (rawKey, value) in self { if let key = rawKey as? String, let opt = NSDictionary.keyValueToSocketIOClientOption(key: key, value: value) { options.insert(opt) } } - + return options } } extension String { func toArray() throws -> [Any] { - guard let stringData = data(using: .utf8, allowLossyConversion: false) else { return [] } + guard let stringData = data(using: .utf16, allowLossyConversion: false) else { return [] } guard let array = try JSONSerialization.jsonObject(with: stringData, options: .mutableContainers) as? [Any] else { throw JSONError.notArray } - + return array } - + func toNSDictionary() throws -> NSDictionary { - guard let binData = data(using: .utf8, allowLossyConversion: false) else { return [:] } + guard let binData = data(using: .utf16, allowLossyConversion: false) else { return [:] } guard let json = try JSONSerialization.jsonObject(with: binData, options: .allowFragments) as? NSDictionary else { throw JSONError.notNSDictionary } - + return json } - + func urlEncode() -> String? { return addingPercentEncoding(withAllowedCharacters: .allowedURLCharacterSet) } diff --git a/Source/SocketIOClientOption.swift b/Source/SocketIOClientOption.swift index 119a71c..f594b6b 100644 --- a/Source/SocketIOClientOption.swift +++ b/Source/SocketIOClientOption.swift @@ -36,8 +36,8 @@ public enum SocketIOClientOption : ClientOption { /// An array of cookies that will be sent during the initial connection. case cookies([HTTPCookie]) - /// The node.js socket.io currently does funky things to unicode when doing HTTP long-polling. Passing `true` in - /// this option causes the client to try and fix any bad unicode that might be sent. + /// Deprecated + @available(*, deprecated, message: "No longer needed in socket.io 2.0+") case doubleEncodeUTF8(Bool) /// Any extra HTTP headers that should be sent during the initial connection. diff --git a/Source/SocketParsable.swift b/Source/SocketParsable.swift index 28b431d..5c698dc 100644 --- a/Source/SocketParsable.swift +++ b/Source/SocketParsable.swift @@ -107,7 +107,7 @@ extension SocketParsable where Self: SocketIOClientSpec { } } - var dataArray = message[message.characters.index(reader.currentIndex, offsetBy: 1).. String.Index { - currentIndex = message.characters.index(currentIndex, offsetBy: by) - + mutating func advance(by: Int) -> String.UTF16View.Index { + currentIndex = message.utf16.index(currentIndex, offsetBy: by) + return currentIndex } - + mutating func read(count: Int) -> String { - let readString = message[currentIndex.. String { - let substring = message[currentIndex.. String { - return read(count: message.characters.distance(from: currentIndex, to: message.endIndex)) + return read(count: message.utf16.distance(from: currentIndex, to: message.utf16.endIndex)) } }