@@ -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 do Disconnect( 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-
764772private class SSLCert {
765773 var certData : NSData ?
766774 var key : SecKeyRef ?
0 commit comments