Skip to content

Commit bcb556b

Browse files
committed
bump websocket
1 parent d8b5293 commit bcb556b

File tree

3 files changed

+79
-72
lines changed

3 files changed

+79
-72
lines changed

Source/SocketEngineSpec.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,8 @@ import Foundation
6161

6262
extension SocketEngineSpec {
6363
func createBinaryDataForSend(data: NSData) -> Either<NSData, String> {
64-
if websocket {
65-
var byteArray = [UInt8](count: 1, repeatedValue: 0x0)
66-
byteArray[0] = 4
64+
if websocket {
65+
var byteArray = [UInt8](count: 1, repeatedValue: 0x4)
6766
let mutData = NSMutableData(bytes: &byteArray, length: 1)
6867

6968
mutData.appendData(data)

Source/SocketIOClient.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable
100100

101101
/**
102102
Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity.
103-
If using Swift it's recommended to use `init(var socketURL: String, opts: SocketOptionsDictionary? = nil)`
103+
If using Swift it's recommended to use `init(var socketURL: String, options: Set<SocketIOClientOption>)`
104104
*/
105105
public convenience init(socketURL: String, options: NSDictionary?) {
106106
self.init(socketURL: socketURL,

Source/WebSocket.swift

Lines changed: 76 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,14 @@ public class WebSocket : NSObject, NSStreamDelegate {
111111
public var selfSignedSSL = false
112112
private var security: SSLSecurity?
113113
public var enabledSSLCipherSuites: [SSLCipherSuite]?
114+
public var origin: String?
114115
public var isConnected :Bool {
115116
return connected
116117
}
118+
public var currentURL: NSURL {return url}
117119
private var url: NSURL
118120
private var inputStream: NSInputStream?
119121
private var outputStream: NSOutputStream?
120-
private var isRunLoop = false
121122
private var connected = false
122123
private var isCreated = false
123124
private var writeQueue = NSOperationQueue()
@@ -126,26 +127,24 @@ public class WebSocket : NSObject, NSStreamDelegate {
126127
private var fragBuffer: NSData?
127128
private var certValidated = false
128129
private var didDisconnect = false
130+
//the shared processing queue used for all websocket
131+
private static let sharedWorkQueue = dispatch_queue_create("com.vluxe.starscream.websocket", DISPATCH_QUEUE_SERIAL)
129132

130133
//used for setting protocols.
131134
public init(url: NSURL, protocols: [String]? = nil) {
132135
self.url = url
136+
self.origin = url.absoluteString
133137
writeQueue.maxConcurrentOperationCount = 1
134138
optionalProtocols = protocols
135139
}
136140

137141
///Connect to the websocket server on a background thread
138142
public func connect() {
139143
guard !isCreated else { return }
140-
141-
dispatch_async(queue) { [weak self] in
142-
self?.didDisconnect = false
143-
}
144-
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)) { [weak self] in
145-
self?.isCreated = true
146-
self?.createHTTPRequest()
147-
self?.isCreated = false
148-
}
144+
didDisconnect = false
145+
isCreated = true
146+
createHTTPRequest()
147+
isCreated = false
149148
}
150149

151150
/**
@@ -175,20 +174,22 @@ public class WebSocket : NSObject, NSStreamDelegate {
175174

176175
///write a string to the websocket. This sends it as a text frame.
177176
public func writeString(str: String) {
177+
guard isConnected else { return }
178178
dequeueWrite(str.dataUsingEncoding(NSUTF8StringEncoding)!, code: .TextFrame)
179179
}
180180

181181
///write binary data to the websocket. This sends it as a binary frame.
182182
public func writeData(data: NSData) {
183+
guard isConnected else { return }
183184
dequeueWrite(data, code: .BinaryFrame)
184185
}
185186

186187
//write a ping to the websocket. This sends it as a control frame.
187188
//yodel a sound to the planet. This sends it as an astroid. http://youtu.be/Eu5ZJELRiJ8?t=42s
188189
public func writePing(data: NSData) {
190+
guard isConnected else { return }
189191
dequeueWrite(data, code: .Ping)
190192
}
191-
//private methods below!
192193

193194
//private method that starts the connection
194195
private func createHTTPRequest() {
@@ -211,7 +212,9 @@ public class WebSocket : NSObject, NSStreamDelegate {
211212
}
212213
addHeader(urlRequest, key: headerWSVersionName, val: headerWSVersionValue)
213214
addHeader(urlRequest, key: headerWSKeyName, val: generateWebSocketKey())
214-
addHeader(urlRequest, key: headerOriginName, val: url.absoluteString)
215+
if let origin = origin {
216+
addHeader(urlRequest, key: headerOriginName, val: origin)
217+
}
215218
addHeader(urlRequest, key: headerWSHostName, val: "\(url.host!):\(port!)")
216219
for (key,value) in headers {
217220
addHeader(urlRequest, key: key, val: value)
@@ -221,10 +224,12 @@ public class WebSocket : NSObject, NSStreamDelegate {
221224
initStreamsWithData(serializedRequest, Int(port!))
222225
}
223226
}
227+
224228
//Add a header to the CFHTTPMessage by using the NSString bridges to CFString
225229
private func addHeader(urlRequest: CFHTTPMessage, key: NSString, val: NSString) {
226230
CFHTTPMessageSetHeaderFieldValue(urlRequest, key, val)
227231
}
232+
228233
//generate a websocket key as needed in rfc
229234
private func generateWebSocketKey() -> String {
230235
var key = ""
@@ -237,6 +242,7 @@ public class WebSocket : NSObject, NSStreamDelegate {
237242
let baseKey = data?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
238243
return baseKey!
239244
}
245+
240246
//Start the stream connection and write the data to the output stream
241247
private func initStreamsWithData(data: NSData, _ port: Int) {
242248
//higher level API we will cut over to at some point
@@ -283,15 +289,16 @@ public class WebSocket : NSObject, NSStreamDelegate {
283289
}
284290
}
285291
}
286-
isRunLoop = true
287-
inStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
288-
outStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
292+
CFReadStreamSetDispatchQueue(inStream, WebSocket.sharedWorkQueue)
293+
CFWriteStreamSetDispatchQueue(outStream, WebSocket.sharedWorkQueue)
289294
inStream.open()
290295
outStream.open()
291296
let bytes = UnsafePointer<UInt8>(data.bytes)
292-
outStream.write(bytes, maxLength: data.length)
293-
while(isRunLoop) {
294-
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate.distantFuture() as NSDate)
297+
writeQueue.addOperationWithBlock {
298+
while !outStream.hasSpaceAvailable {
299+
usleep(100) //wait until the socket is ready
300+
}
301+
outStream.write(bytes, maxLength: data.length)
295302
}
296303
}
297304
//delegate for the stream methods. Processes incoming bytes
@@ -324,18 +331,16 @@ public class WebSocket : NSObject, NSStreamDelegate {
324331
private func disconnectStream(error: NSError?) {
325332
writeQueue.waitUntilAllOperationsAreFinished()
326333
if let stream = inputStream {
327-
stream.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
334+
CFReadStreamSetDispatchQueue(stream, nil)
328335
stream.close()
329336
}
330337
if let stream = outputStream {
331-
stream.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
338+
CFWriteStreamSetDispatchQueue(stream, nil)
332339
stream.close()
333340
}
334341
outputStream = nil
335-
isRunLoop = false
336342
certValidated = false
337343
doDisconnect(error)
338-
connected = false
339344
}
340345

341346
///handles the incoming bytes and sending them to the proper processing method
@@ -345,24 +350,13 @@ public class WebSocket : NSObject, NSStreamDelegate {
345350
let length = inputStream!.read(buffer, maxLength: BUFFER_MAX)
346351

347352
guard length > 0 else { return }
348-
349-
if !connected {
350-
connected = processHTTP(buffer, bufferLen: length)
351-
if !connected {
352-
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue()
353-
CFHTTPMessageAppendBytes(response, buffer, length)
354-
let code = CFHTTPMessageGetResponseStatusCode(response)
355-
doDisconnect(errorWithDetail("Invalid HTTP upgrade", code: UInt16(code)))
356-
}
357-
} else {
358-
var process = false
359-
if inputQueue.count == 0 {
360-
process = true
361-
}
362-
inputQueue.append(NSData(bytes: buffer, length: length))
363-
if process {
364-
dequeueInput()
365-
}
353+
var process = false
354+
if inputQueue.count == 0 {
355+
process = true
356+
}
357+
inputQueue.append(NSData(bytes: buffer, length: length))
358+
if process {
359+
dequeueInput()
366360
}
367361
}
368362
///dequeue the incoming input so it is processed in order
@@ -378,12 +372,34 @@ public class WebSocket : NSObject, NSStreamDelegate {
378372
self.fragBuffer = nil
379373
}
380374
let buffer = UnsafePointer<UInt8>(work.bytes)
381-
processRawMessage(buffer, bufferLen: work.length)
375+
let length = work.length
376+
if !connected {
377+
processTCPHandshake(buffer, bufferLen: length)
378+
} else {
379+
processRawMessage(buffer, bufferLen: length)
380+
}
382381
inputQueue = inputQueue.filter{$0 != data}
383382
dequeueInput()
384383
}
384+
385+
//handle checking the inital connection status
386+
private func processTCPHandshake(buffer: UnsafePointer<UInt8>, bufferLen: Int) {
387+
let code = processHTTP(buffer, bufferLen: bufferLen)
388+
switch code {
389+
case 0:
390+
connected = true
391+
dispatch_async(queue) { [weak self] in
392+
guard let s = self else { return }
393+
s.onConnect?()
394+
s.delegate?.websocketDidConnect(s)
395+
}
396+
case -1: break //do nothing, we are going to collect more data
397+
default:
398+
doDisconnect(errorWithDetail("Invalid HTTP upgrade", code: UInt16(code)))
399+
}
400+
}
385401
///Finds the HTTP Packet in the TCP stream, by looking for the CRLF.
386-
private func processHTTP(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool {
402+
private func processHTTP(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Int {
387403
let CRLFBytes = [UInt8(ascii: "\r"), UInt8(ascii: "\n"), UInt8(ascii: "\r"), UInt8(ascii: "\n")]
388404
var k = 0
389405
var totalSize = 0
@@ -399,39 +415,37 @@ public class WebSocket : NSObject, NSStreamDelegate {
399415
}
400416
}
401417
if totalSize > 0 {
402-
if validateResponse(buffer, bufferLen: totalSize) {
403-
dispatch_async(queue) { [weak self] in
404-
guard let s = self else { return }
405-
s.onConnect?()
406-
s.delegate?.websocketDidConnect(s)
407-
}
408-
totalSize += 1 //skip the last \n
409-
let restSize = bufferLen - totalSize
410-
if restSize > 0 {
411-
processRawMessage((buffer+totalSize),bufferLen: restSize)
412-
}
413-
return true
418+
let code = validateResponse(buffer, bufferLen: totalSize)
419+
if code != 0 {
420+
return code
421+
}
422+
totalSize += 1 //skip the last \n
423+
let restSize = bufferLen - totalSize
424+
if restSize > 0 {
425+
processRawMessage((buffer+totalSize),bufferLen: restSize)
414426
}
427+
return 0 //success
415428
}
416-
return false
429+
return -1 //was unable to find the full TCP header
417430
}
418431

419432
///validates the HTTP is a 101 as per the RFC spec
420-
private func validateResponse(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool {
433+
private func validateResponse(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Int {
421434
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue()
422435
CFHTTPMessageAppendBytes(response, buffer, bufferLen)
423-
if CFHTTPMessageGetResponseStatusCode(response) != 101 {
424-
return false
436+
let code = CFHTTPMessageGetResponseStatusCode(response)
437+
if code != 101 {
438+
return code
425439
}
426440
if let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response) {
427441
let headers = cfHeaders.takeRetainedValue() as NSDictionary
428442
if let acceptKey = headers[headerWSAcceptName] as? NSString {
429443
if acceptKey.length > 0 {
430-
return true
444+
return 0
431445
}
432446
}
433447
}
434-
return false
448+
return -1
435449
}
436450

437451
///read a 16 bit big endian value from a buffer
@@ -687,8 +701,6 @@ public class WebSocket : NSObject, NSStreamDelegate {
687701
}
688702
///used to write things to the stream
689703
private func dequeueWrite(data: NSData, code: OpCode) {
690-
guard isConnected else { return }
691-
692704
writeQueue.addOperationWithBlock { [weak self] in
693705
//stream isn't ready, let's wait
694706
guard let s = self else { return }
@@ -720,9 +732,6 @@ public class WebSocket : NSObject, NSStreamDelegate {
720732
}
721733
var total = 0
722734
while true {
723-
if !s.isConnected {
724-
break
725-
}
726735
guard let outStream = s.outputStream else { break }
727736
let writeBuffer = UnsafePointer<UInt8>(frame!.bytes+total)
728737
let len = outStream.write(writeBuffer, maxLength: offset-total)
@@ -750,17 +759,16 @@ public class WebSocket : NSObject, NSStreamDelegate {
750759
///used to preform the disconnect delegate
751760
private func doDisconnect(error: NSError?) {
752761
guard !didDisconnect else { return }
753-
762+
didDisconnect = true
763+
connected = false
754764
dispatch_async(queue) { [weak self] in
755765
guard let s = self else { return }
756-
s.didDisconnect = true
757766
s.onDisconnect?(error)
758767
s.delegate?.websocketDidDisconnect(s, error: error)
759768
}
760769
}
761770

762771
}
763-
764772
private class SSLCert {
765773
var certData: NSData?
766774
var key: SecKeyRef?

0 commit comments

Comments
 (0)