WebSockets.swift 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. //
  2. // HttpHandlers+WebSockets.swift
  3. // Swifter
  4. //
  5. // Copyright © 2014-2016 Damian Kołakowski. All rights reserved.
  6. //
  7. import Foundation
  8. public func websocket(
  9. _ text: ((WebSocketSession, String) -> Void)?,
  10. _ binary: ((WebSocketSession, [UInt8]) -> Void)?) -> ((HttpRequest) -> HttpResponse) {
  11. return { r in
  12. guard r.hasTokenForHeader("upgrade", token: "websocket") else {
  13. return .badRequest(.text("Invalid value of 'Upgrade' header: \(r.headers["upgrade"])"))
  14. }
  15. guard r.hasTokenForHeader("connection", token: "upgrade") else {
  16. return .badRequest(.text("Invalid value of 'Connection' header: \(r.headers["connection"])"))
  17. }
  18. guard let secWebSocketKey = r.headers["sec-websocket-key"] else {
  19. return .badRequest(.text("Invalid value of 'Sec-Websocket-Key' header: \(r.headers["sec-websocket-key"])"))
  20. }
  21. let protocolSessionClosure: ((Socket) -> Void) = { socket in
  22. let session = WebSocketSession(socket)
  23. while let frame = try? session.readFrame() {
  24. switch frame.opcode {
  25. case .text:
  26. if let handleText = text {
  27. handleText(session, String.fromUInt8(frame.payload))
  28. }
  29. case .binary:
  30. if let handleBinary = binary {
  31. handleBinary(session, frame.payload)
  32. }
  33. default: break
  34. }
  35. }
  36. }
  37. let secWebSocketAccept = String.toBase64((secWebSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").SHA1())
  38. let headers = [ "Upgrade": "WebSocket", "Connection": "Upgrade", "Sec-WebSocket-Accept": secWebSocketAccept]
  39. return HttpResponse.switchProtocols(headers, protocolSessionClosure)
  40. }
  41. }
  42. public class WebSocketSession {
  43. public enum Error: ErrorProtocol { case unknownOpCode(String), unMaskedFrame }
  44. public enum OpCode: UInt8 { case `continue` = 0x00, close = 0x08, ping = 0x09, pong = 0x0A, text = 0x01, binary = 0x02 }
  45. public class Frame {
  46. public var opcode = OpCode.close
  47. public var fin = false
  48. public var payload = [UInt8]()
  49. }
  50. private let socket: Socket
  51. public init(_ socket: Socket) {
  52. self.socket = socket
  53. }
  54. public func writeText(_ text: String) -> Void {
  55. self.writeFrame(ArraySlice(text.utf8), OpCode.text)
  56. }
  57. public func writeBinary(_ binary: [UInt8]) -> Void {
  58. self.writeBinary(ArraySlice(binary))
  59. }
  60. public func writeBinary(_ binary: ArraySlice<UInt8>) -> Void {
  61. self.writeFrame(binary, OpCode.binary)
  62. }
  63. private func writeFrame(_ data: ArraySlice<UInt8>, _ op: OpCode, _ fin: Bool = true) {
  64. let finAndOpCode = UInt8(fin ? 0x80 : 0x00) | op.rawValue
  65. let maskAndLngth = encodeLengthAndMaskFlag(UInt64(data.count), false)
  66. do {
  67. try self.socket.writeUInt8([finAndOpCode])
  68. try self.socket.writeUInt8(maskAndLngth)
  69. try self.socket.writeUInt8(data)
  70. } catch {
  71. print(error)
  72. }
  73. }
  74. private func encodeLengthAndMaskFlag(_ len: UInt64, _ masked: Bool) -> [UInt8] {
  75. let encodedLngth = UInt8(masked ? 0x80 : 0x00)
  76. var encodedBytes = [UInt8]()
  77. switch len {
  78. case 0...125:
  79. encodedBytes.append(encodedLngth | UInt8(len));
  80. case 126...UInt64(UINT16_MAX):
  81. encodedBytes.append(encodedLngth | 0x7E);
  82. encodedBytes.append(UInt8(len >> 8));
  83. encodedBytes.append(UInt8(len & 0xFF));
  84. default:
  85. encodedBytes.append(encodedLngth | 0x7F);
  86. encodedBytes.append(UInt8(len >> 56) & 0xFF);
  87. encodedBytes.append(UInt8(len >> 48) & 0xFF);
  88. encodedBytes.append(UInt8(len >> 40) & 0xFF);
  89. encodedBytes.append(UInt8(len >> 32) & 0xFF);
  90. encodedBytes.append(UInt8(len >> 24) & 0xFF);
  91. encodedBytes.append(UInt8(len >> 16) & 0xFF);
  92. encodedBytes.append(UInt8(len >> 08) & 0xFF);
  93. encodedBytes.append(UInt8(len >> 00) & 0xFF);
  94. }
  95. return encodedBytes
  96. }
  97. public func readFrame() throws -> Frame {
  98. let frm = Frame()
  99. let fst = try socket.read()
  100. frm.fin = fst & 0x80 != 0
  101. let opc = fst & 0x0F
  102. guard let opcode = OpCode(rawValue: opc) else {
  103. // "If an unknown opcode is received, the receiving endpoint MUST _Fail the WebSocket Connection_."
  104. // http://tools.ietf.org/html/rfc6455#section-5.2 ( Page 29 )
  105. throw Error.unknownOpCode("\(opc)")
  106. }
  107. frm.opcode = opcode
  108. let sec = try socket.read()
  109. let msk = sec & 0x80 != 0
  110. guard msk else {
  111. // "...a client MUST mask all frames that it sends to the serve.."
  112. // http://tools.ietf.org/html/rfc6455#section-5.1
  113. throw Error.unMaskedFrame
  114. }
  115. var len = UInt64(sec & 0x7F)
  116. if len == 0x7E {
  117. let b0 = UInt64(try socket.read())
  118. let b1 = UInt64(try socket.read())
  119. len = UInt64(littleEndian: b0 << 8 | b1)
  120. } else if len == 0x7F {
  121. let b0 = UInt64(try socket.read())
  122. let b1 = UInt64(try socket.read())
  123. let b2 = UInt64(try socket.read())
  124. let b3 = UInt64(try socket.read())
  125. let b4 = UInt64(try socket.read())
  126. let b5 = UInt64(try socket.read())
  127. let b6 = UInt64(try socket.read())
  128. let b7 = UInt64(try socket.read())
  129. len = UInt64(littleEndian: b0 << 54 | b1 << 48 | b2 << 40 | b3 << 32 | b4 << 24 | b5 << 16 | b6 << 8 | b7)
  130. }
  131. let mask = [try socket.read(), try socket.read(), try socket.read(), try socket.read()]
  132. for i in 0..<len {
  133. frm.payload.append(try socket.read() ^ mask[Int(i % 4)])
  134. }
  135. return frm
  136. }
  137. }