1
0

HttpServerIO.swift 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. //
  2. // HttpServer.swift
  3. // Swifter
  4. //
  5. // Copyright (c) 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 class HttpServerIO {
  13. private var listenSocket: Socket = Socket(socketFileDescriptor: -1)
  14. private var clientSockets: Set<Socket> = []
  15. private let clientSocketsLock = Lock()
  16. public typealias MiddlewareCallback = (HttpRequest) -> HttpResponse?
  17. public var middleware = [MiddlewareCallback]()
  18. @available(OSX 10.10, *)
  19. public func start(_ listenPort: in_port_t = 8080, forceIPv4: Bool = false) throws {
  20. stop()
  21. listenSocket = try Socket.tcpSocketForListen(listenPort, forceIPv4: forceIPv4)
  22. DispatchQueue.global(attributes: DispatchQueue.GlobalAttributes.qosBackground).async {
  23. while let socket = try? self.listenSocket.acceptClientSocket() {
  24. self.lock(self.clientSocketsLock) {
  25. self.clientSockets.insert(socket)
  26. }
  27. DispatchQueue.global(attributes: DispatchQueue.GlobalAttributes.qosBackground).async {
  28. self.handleConnection(socket)
  29. self.lock(self.clientSocketsLock) {
  30. self.clientSockets.remove(socket)
  31. }
  32. }
  33. }
  34. self.stop()
  35. }
  36. }
  37. public func stop() {
  38. listenSocket.release()
  39. lock(self.clientSocketsLock) {
  40. for socket in self.clientSockets {
  41. socket.shutdwn()
  42. }
  43. self.clientSockets.removeAll(keepingCapacity: true)
  44. }
  45. }
  46. public func dispatch(_ method: String, path: String) -> ([String: String], (HttpRequest) -> HttpResponse) {
  47. return ([:], { _ in HttpResponse.NotFound })
  48. }
  49. private func handleConnection(_ socket: Socket) {
  50. let address = try? socket.peername()
  51. let parser = HttpParser()
  52. while let request = try? parser.readHttpRequest(socket) {
  53. request.address = address
  54. var response = askMiddlewareForResponse(request)
  55. if response == nil {
  56. let (params, handler) = self.dispatch(request.method, path: request.path)
  57. request.params = params
  58. response = handler(request)
  59. }
  60. var keepConnection = parser.supportsKeepAlive(request.headers)
  61. do {
  62. keepConnection = try self.respond(socket, response: response!, keepAlive: keepConnection)
  63. } catch {
  64. print("Failed to send response: \(error)")
  65. break
  66. }
  67. if let session = response!.socketSession() {
  68. session(socket)
  69. break
  70. }
  71. if !keepConnection { break }
  72. }
  73. socket.release()
  74. }
  75. private func askMiddlewareForResponse(_ request: HttpRequest) -> HttpResponse? {
  76. for layer in middleware {
  77. if let response = layer(request) {
  78. return response
  79. }
  80. }
  81. return nil
  82. }
  83. private func lock(_ handle: Lock, closure: () -> ()) {
  84. handle.lock()
  85. closure()
  86. handle.unlock();
  87. }
  88. private struct InnerWriteContext: HttpResponseBodyWriter {
  89. let socket: Socket
  90. func write(_ data: [UInt8]) {
  91. write(ArraySlice(data))
  92. }
  93. func write(_ data: ArraySlice<UInt8>) {
  94. do {
  95. try socket.writeUInt8(data)
  96. } catch {
  97. print("\(error)")
  98. }
  99. }
  100. }
  101. private func respond(_ socket: Socket, response: HttpResponse, keepAlive: Bool) throws -> Bool {
  102. try socket.writeUTF8("HTTP/1.1 \(response.statusCode()) \(response.reasonPhrase())\r\n")
  103. let content = response.content()
  104. if content.length >= 0 {
  105. try socket.writeUTF8("Content-Length: \(content.length)\r\n")
  106. }
  107. if keepAlive && content.length != -1 {
  108. try socket.writeUTF8("Connection: keep-alive\r\n")
  109. }
  110. for (name, value) in response.headers() {
  111. try socket.writeUTF8("\(name): \(value)\r\n")
  112. }
  113. try socket.writeUTF8("\r\n")
  114. if let writeClosure = content.write {
  115. let context = InnerWriteContext(socket: socket)
  116. try writeClosure(context)
  117. }
  118. return keepAlive && content.length != -1;
  119. }
  120. }
  121. #if os(Linux)
  122. import Glibc
  123. public class Lock {
  124. private var mutex = pthread_mutex_t()
  125. init() { pthread_mutex_init(&mutex, nil) }
  126. public func lock() { pthread_mutex_lock(&mutex) }
  127. public func unlock() { pthread_mutex_unlock(&mutex) }
  128. deinit { pthread_mutex_destroy(&mutex) }
  129. }
  130. public class DispatchQueue {
  131. private static let instance = DispatchQueue()
  132. public struct GlobalAttributes {
  133. public static let qosBackground: DispatchQueue.GlobalAttributes = GlobalAttributes()
  134. }
  135. public class func global(attributes: DispatchQueue.GlobalAttributes) -> DispatchQueue {
  136. return instance
  137. }
  138. private class DispatchContext {
  139. let block: ((Void) -> Void)
  140. init(_ block: ((Void) -> Void)) {
  141. self.block = block
  142. }
  143. }
  144. public func async(execute work: @convention(block) () -> Swift.Void) {
  145. let context = UnsafeMutablePointer<Void>(OpaquePointer(bitPattern: Unmanaged.passRetained(DispatchContext(work))))
  146. var pthread: pthread_t = 0
  147. pthread_create(&pthread, nil, { (context: UnsafeMutablePointer<Swift.Void>?) -> UnsafeMutablePointer<Swift.Void>? in
  148. if let context = context {
  149. let unmanaged = Unmanaged<DispatchContext>.fromOpaque(OpaquePointer(context))
  150. unmanaged.takeUnretainedValue().block()
  151. unmanaged.release()
  152. }
  153. return nil
  154. }, context)
  155. }
  156. }
  157. #endif