WebSockets.swift 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. //
  2. // HttpHandlers+WebSockets.swift
  3. // Swifter
  4. //
  5. // Copyright © 2014-2016 Damian Kołakowski. All rights reserved.
  6. //
  7. #if os(Linux)
  8. import Glibc
  9. #else
  10. import Foundation
  11. #endif
  12. public func websocket(
  13. text: ((WebSocketSession, String) -> Void)?,
  14. _ binary: ((WebSocketSession, [UInt8]) -> Void)?) -> (HttpRequest -> HttpResponse) {
  15. return { r in
  16. guard r.hasTokenForHeader("upgrade", token: "websocket") else {
  17. return .BadRequest(.Text("Invalid value of 'Upgrade' header: \(r.headers["upgrade"])"))
  18. }
  19. guard r.hasTokenForHeader("connection", token: "upgrade") else {
  20. return .BadRequest(.Text("Invalid value of 'Connection' header: \(r.headers["connection"])"))
  21. }
  22. guard let secWebSocketKey = r.headers["sec-websocket-key"] else {
  23. return .BadRequest(.Text("Invalid value of 'Sec-Websocket-Key' header: \(r.headers["sec-websocket-key"])"))
  24. }
  25. let protocolSessionClosure: (Socket -> Void) = { socket in
  26. let session = WebSocketSession(socket)
  27. do {
  28. while true {
  29. let frame = try session.readFrame()
  30. switch frame.opcode {
  31. case .Text:
  32. if let handleText = text {
  33. handleText(session, String.fromUInt8(frame.payload))
  34. }
  35. case .Binary:
  36. if let handleBinary = binary {
  37. handleBinary(session, frame.payload)
  38. }
  39. case .Close:
  40. session.writeCloseFrame()
  41. case .Continue:
  42. break
  43. case .Ping:
  44. if frame.payload.count > 125 {
  45. throw WebSocketSession.Error.ProtocolError("payload gretter than 125 octets.")
  46. } else {
  47. session.writeFrame(ArraySlice(frame.payload), .Pong)
  48. }
  49. break
  50. case .Pong:
  51. break
  52. }
  53. }
  54. } catch let error {
  55. switch error {
  56. case WebSocketSession.Error.UnknownOpCode:
  57. print("Unknown Op Code: \(error)")
  58. default:
  59. print("Unkown error \(error)")
  60. }
  61. // If an error occurs, send the close handshake.
  62. session.writeCloseFrame()
  63. }
  64. }
  65. let secWebSocketAccept = String.toBase64((secWebSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").SHA1())
  66. let headers = [ "Upgrade": "WebSocket", "Connection": "Upgrade", "Sec-WebSocket-Accept": secWebSocketAccept]
  67. return HttpResponse.SwitchProtocols(headers, protocolSessionClosure)
  68. }
  69. }
  70. public class WebSocketSession: Hashable, Equatable {
  71. public enum Error: ErrorType { case UnknownOpCode(String), UnMaskedFrame, ProtocolError(String) }
  72. public enum OpCode: UInt8 { case Continue = 0x00, Close = 0x08, Ping = 0x09, Pong = 0x0A, Text = 0x01, Binary = 0x02 }
  73. public class Frame {
  74. public var opcode = OpCode.Close
  75. public var fin = false
  76. public var payload = [UInt8]()
  77. }
  78. private let socket: Socket
  79. public init(_ socket: Socket) {
  80. self.socket = socket
  81. }
  82. deinit {
  83. writeCloseFrame()
  84. }
  85. public func writeText(text: String) -> Void {
  86. self.writeFrame(ArraySlice(text.utf8), OpCode.Text)
  87. }
  88. public func writeBinary(binary: [UInt8]) -> Void {
  89. self.writeBinary(ArraySlice(binary))
  90. }
  91. public func writeBinary(binary: ArraySlice<UInt8>) -> Void {
  92. self.writeFrame(binary, OpCode.Binary)
  93. }
  94. private func writeFrame(data: ArraySlice<UInt8>, _ op: OpCode, _ fin: Bool = true) {
  95. let finAndOpCode = UInt8(fin ? 0x80 : 0x00) | op.rawValue
  96. let maskAndLngth = encodeLengthAndMaskFlag(UInt64(data.count), false)
  97. do {
  98. try self.socket.writeUInt8([finAndOpCode])
  99. try self.socket.writeUInt8(maskAndLngth)
  100. try self.socket.writeUInt8(data)
  101. } catch {
  102. print(error)
  103. }
  104. }
  105. private func writeCloseFrame() {
  106. writeFrame(ArraySlice("".utf8), .Close)
  107. }
  108. private func encodeLengthAndMaskFlag(len: UInt64, _ masked: Bool) -> [UInt8] {
  109. let encodedLngth = UInt8(masked ? 0x80 : 0x00)
  110. var encodedBytes = [UInt8]()
  111. switch len {
  112. case 0...125:
  113. encodedBytes.append(encodedLngth | UInt8(len));
  114. case 126...UInt64(UINT16_MAX):
  115. encodedBytes.append(encodedLngth | 0x7E);
  116. encodedBytes.append(UInt8(len >> 8 & 0xFF));
  117. encodedBytes.append(UInt8(len >> 0 & 0xFF));
  118. default:
  119. encodedBytes.append(encodedLngth | 0x7F);
  120. encodedBytes.append(UInt8(len >> 56 & 0xFF));
  121. encodedBytes.append(UInt8(len >> 48 & 0xFF));
  122. encodedBytes.append(UInt8(len >> 40 & 0xFF));
  123. encodedBytes.append(UInt8(len >> 32 & 0xFF));
  124. encodedBytes.append(UInt8(len >> 24 & 0xFF));
  125. encodedBytes.append(UInt8(len >> 16 & 0xFF));
  126. encodedBytes.append(UInt8(len >> 08 & 0xFF));
  127. encodedBytes.append(UInt8(len >> 00 & 0xFF));
  128. }
  129. return encodedBytes
  130. }
  131. public func readFrame() throws -> Frame {
  132. let frm = Frame()
  133. let fst = try socket.read()
  134. frm.fin = fst & 0x80 != 0
  135. let opc = fst & 0x0F
  136. guard let opcode = OpCode(rawValue: opc) else {
  137. // "If an unknown opcode is received, the receiving endpoint MUST _Fail the WebSocket Connection_."
  138. // http://tools.ietf.org/html/rfc6455#section-5.2 ( Page 29 )
  139. throw Error.UnknownOpCode("\(opc)")
  140. }
  141. frm.opcode = opcode
  142. let sec = try socket.read()
  143. let msk = sec & 0x80 != 0
  144. guard msk else {
  145. // "...a client MUST mask all frames that it sends to the server."
  146. // http://tools.ietf.org/html/rfc6455#section-5.1
  147. throw Error.UnMaskedFrame
  148. }
  149. var len = UInt64(sec & 0x7F)
  150. if len == 0x7E {
  151. let b0 = UInt64(try socket.read())
  152. let b1 = UInt64(try socket.read())
  153. len = UInt64(littleEndian: b0 << 8 | b1)
  154. } else if len == 0x7F {
  155. let b0 = UInt64(try socket.read())
  156. let b1 = UInt64(try socket.read())
  157. let b2 = UInt64(try socket.read())
  158. let b3 = UInt64(try socket.read())
  159. let b4 = UInt64(try socket.read())
  160. let b5 = UInt64(try socket.read())
  161. let b6 = UInt64(try socket.read())
  162. let b7 = UInt64(try socket.read())
  163. len = UInt64(littleEndian: b0 << 54 | b1 << 48 | b2 << 40 | b3 << 32 | b4 << 24 | b5 << 16 | b6 << 8 | b7)
  164. }
  165. let mask = [try socket.read(), try socket.read(), try socket.read(), try socket.read()]
  166. for i in 0..<len {
  167. frm.payload.append(try socket.read() ^ mask[Int(i % 4)])
  168. }
  169. return frm
  170. }
  171. public var hashValue: Int {
  172. get {
  173. return socket.hashValue
  174. }
  175. }
  176. }
  177. public func ==(webSocketSession1: WebSocketSession, webSocketSession2: WebSocketSession) -> Bool {
  178. return webSocketSession1.socket == webSocketSession2.socket
  179. }