WebSockets.swift 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. public required init(integerLiteral value: Int) {
  46. fatalError("init(integerLiteral:) has not been implemented")
  47. }
  48. }
  49. public class WebSocketFrame {
  50. public enum OpCode: UInt8 {
  51. case `continue` = 0x00
  52. case close = 0x08
  53. case ping = 0x09
  54. case pong = 0x0A
  55. case text = 0x01
  56. case binary = 0x02
  57. }
  58. public init(_ opcode: OpCode, _ payload: [UInt8]) {
  59. self.opcode = opcode
  60. self.payload = payload
  61. }
  62. public let opcode: OpCode
  63. public let payload: [UInt8]
  64. }
  65. public class WebsocketFramesProcessor {
  66. private let closure: ((WebsocketEvent) -> Void)
  67. public init(_ closure: @escaping ((WebsocketEvent) -> Void)) {
  68. self.closure = closure
  69. }
  70. public func process(_ frame: WebSocketFrame) throws {
  71. switch frame.opcode {
  72. case .text:
  73. if let text = String(bytes: frame.payload, encoding: .utf8) {
  74. self.closure(.text(text))
  75. } else {
  76. print("Invalid payload (not utf8): \(frame.payload)")
  77. }
  78. case .binary:
  79. self.closure(.binary(frame.payload))
  80. default:
  81. throw WebSocketError.notImplemented("Not able to handle: \(frame.opcode.rawValue)")
  82. }
  83. }
  84. }
  85. public class WebsocketDataPorcessor: IncomingDataProcessor {
  86. private let framesProcessor: WebsocketFramesProcessor
  87. public init(_ framesProcessor: WebsocketFramesProcessor) {
  88. self.framesProcessor = framesProcessor
  89. }
  90. private var stack = [UInt8]()
  91. public func process(_ chunk: ArraySlice<UInt8>) throws {
  92. stack.append(contentsOf: chunk)
  93. guard stack.count > 1 else { return }
  94. _ = stack[0] & 0x80 != 0
  95. let opc = stack[0] & 0x0F
  96. guard let opcode = WebSocketFrame.OpCode(rawValue: opc) else {
  97. // "If an unknown opcode is received, the receiving endpoint MUST _Fail the WebSocket Connection_."
  98. // http://tools.ietf.org/html/rfc6455#section-5.2 ( Page 29 )
  99. throw WebSocketError.unknownOpCode("\(opc)")
  100. }
  101. let msk = stack[1] & 0x80 != 0
  102. guard msk else {
  103. // "...a client MUST mask all frames that it sends to the serve.."
  104. // http://tools.ietf.org/html/rfc6455#section-5.1
  105. throw WebSocketError.unMaskedFrame
  106. }
  107. var len = UInt64(stack[1] & 0x7F)
  108. var offset = 2
  109. if len == 0x7E {
  110. guard stack.count > 3 else { return }
  111. let b0 = UInt64(stack[2])
  112. let b1 = UInt64(stack[3])
  113. len = UInt64(littleEndian: b0 << 8 | b1)
  114. offset = 4
  115. } else if len == 0x7F {
  116. guard stack.count > 9 else { return }
  117. let b0 = UInt64(stack[2])
  118. let b1 = UInt64(stack[3])
  119. let b2 = UInt64(stack[4])
  120. let b3 = UInt64(stack[5])
  121. let b4 = UInt64(stack[6])
  122. let b5 = UInt64(stack[7])
  123. let b6 = UInt64(stack[8])
  124. let b7 = UInt64(stack[9])
  125. len = UInt64(littleEndian: b0 << 54 | b1 << 48 | b2 << 40 | b3 << 32 | b4 << 24 | b5 << 16 | b6 << 8 | b7)
  126. offset = 10
  127. }
  128. guard (len + UInt64(offset) + 4) >= UInt64(stack.count) else {
  129. return
  130. }
  131. let mask = [stack[offset], stack[offset+1], stack[offset+2], stack[offset+3]]
  132. offset = offset + mask.count
  133. let payload = stack[offset..<(offset + Int(len /* //TODO fix this */))].enumerated().map { $0.element ^ mask[Int($0.offset % 4)] }
  134. stack.removeFirst(offset+Int(len))
  135. try framesProcessor.process(WebSocketFrame(opcode, payload))
  136. }
  137. }