WebSockets.swift 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. //
  2. // WebSockets.swift
  3. // Swifter
  4. //
  5. // Copyright © 2016 Damian Kolakowski. All rights reserved.
  6. //
  7. import Foundation
  8. public enum WebSocketError: Error {
  9. case unknownOpCode(String)
  10. case unMaskedFrame
  11. case notImplemented(String)
  12. }
  13. public enum WebsocketEvent {
  14. case disconnected(Int, String)
  15. case text(String)
  16. case binary([UInt8])
  17. }
  18. public class WebsocketResponse: Response {
  19. public init(_ request: Request, _ closure: @escaping ((WebsocketEvent) -> Void)) {
  20. super.init()
  21. guard request.hasToken("websocket", forHeader: "upgrade") else {
  22. self.status = Status.badRequest.rawValue
  23. self.body = [UInt8](("Invalid value of 'Upgrade' header.").utf8)
  24. return
  25. }
  26. guard request.hasToken("upgrade", forHeader: "connection") else {
  27. self.status = Status.badRequest.rawValue
  28. self.body = [UInt8](("Invalid value of 'Connection' header.").utf8)
  29. return
  30. }
  31. guard let (_, secWebSocketKey) = request.headers.filter({ $0.0 == "sec-websocket-key" }).first else {
  32. self.status = Status.badRequest.rawValue
  33. self.body = [UInt8](("Invalid value of 'Sec-Websocket-Key' header.").utf8)
  34. return
  35. }
  36. guard let secWebSocketAccept = String.toBase64((secWebSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").sha1()) else {
  37. self.status = Status.internalServerError.rawValue
  38. self.body = [UInt8](("Failed to convert websocket key value to base64.").utf8)
  39. return
  40. }
  41. self.status = Status.switchingProtocols.rawValue
  42. self.headers = [ ("Upgrade", "WebSocket"), ("Connection", "Upgrade"), ("Sec-WebSocket-Accept", secWebSocketAccept)]
  43. self.processingSuccesor = WebsocketDataPorcessor(WebsocketFramesProcessor(closure))
  44. }
  45. }
  46. public class WebSocketFrame {
  47. public enum OpCode: UInt8 {
  48. case `continue` = 0x00
  49. case close = 0x08
  50. case ping = 0x09
  51. case pong = 0x0A
  52. case text = 0x01
  53. case binary = 0x02
  54. }
  55. public init(_ opcode: OpCode, _ payload: [UInt8]) {
  56. self.opcode = opcode
  57. self.payload = payload
  58. }
  59. public let opcode: OpCode
  60. public let payload: [UInt8]
  61. }
  62. public class WebsocketFramesProcessor {
  63. private let closure: ((WebsocketEvent) -> Void)
  64. public init(_ closure: @escaping ((WebsocketEvent) -> Void)) {
  65. self.closure = closure
  66. }
  67. public func process(_ frame: WebSocketFrame) throws {
  68. switch frame.opcode {
  69. case .text:
  70. if let text = String(bytes: frame.payload, encoding: .utf8) {
  71. self.closure(.text(text))
  72. } else {
  73. print("Invalid payload (not utf8): \(frame.payload)")
  74. }
  75. case .binary:
  76. self.closure(.binary(frame.payload))
  77. default:
  78. throw WebSocketError.notImplemented("Not able to handle: \(frame.opcode.rawValue)")
  79. }
  80. }
  81. }
  82. public class WebsocketDataPorcessor: IncomingDataProcessor {
  83. private let framesProcessor: WebsocketFramesProcessor
  84. public init(_ framesProcessor: WebsocketFramesProcessor) {
  85. self.framesProcessor = framesProcessor
  86. }
  87. private var stack = [UInt8]()
  88. public func process(_ chunk: ArraySlice<UInt8>) throws {
  89. stack.append(contentsOf: chunk)
  90. guard stack.count > 1 else { return }
  91. _ = stack[0] & 0x80 != 0
  92. let opc = stack[0] & 0x0F
  93. guard let opcode = WebSocketFrame.OpCode(rawValue: opc) else {
  94. // "If an unknown opcode is received, the receiving endpoint MUST _Fail the WebSocket Connection_."
  95. // http://tools.ietf.org/html/rfc6455#section-5.2 ( Page 29 )
  96. throw WebSocketError.unknownOpCode("\(opc)")
  97. }
  98. let msk = stack[1] & 0x80 != 0
  99. guard msk else {
  100. // "...a client MUST mask all frames that it sends to the serve.."
  101. // http://tools.ietf.org/html/rfc6455#section-5.1
  102. throw WebSocketError.unMaskedFrame
  103. }
  104. var len = UInt64(stack[1] & 0x7F)
  105. var offset = 2
  106. if len == 0x7E {
  107. guard stack.count > 3 else { return }
  108. let b0 = UInt64(stack[2])
  109. let b1 = UInt64(stack[3])
  110. len = UInt64(littleEndian: b0 << 8 | b1)
  111. offset = 4
  112. } else if len == 0x7F {
  113. guard stack.count > 9 else { return }
  114. let b0 = UInt64(stack[2])
  115. let b1 = UInt64(stack[3])
  116. let b2 = UInt64(stack[4])
  117. let b3 = UInt64(stack[5])
  118. let b4 = UInt64(stack[6])
  119. let b5 = UInt64(stack[7])
  120. let b6 = UInt64(stack[8])
  121. let b7 = UInt64(stack[9])
  122. len = UInt64(littleEndian: b0 << 54 | b1 << 48 | b2 << 40 | b3 << 32 | b4 << 24 | b5 << 16 | b6 << 8 | b7)
  123. offset = 10
  124. }
  125. guard (len + UInt64(offset) + 4) >= UInt64(stack.count) else {
  126. return
  127. }
  128. let mask = [stack[offset], stack[offset+1], stack[offset+2], stack[offset+3]]
  129. offset = offset + mask.count
  130. let payload = stack[offset..<(offset + Int(len /* //TODO fix this */))].enumerated().map { $0.element ^ mask[Int($0.offset % 4)] }
  131. stack.removeFirst(offset+Int(len))
  132. try framesProcessor.process(WebSocketFrame(opcode, payload))
  133. }
  134. }