1
0

HttpServerIO.swift 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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 socket = Socket(socketFileDescriptor: -1)
  14. private var sockets = Set<Socket>()
  15. public private(set) var running = false
  16. public func port() throws -> Int {
  17. return Int(try socket.port())
  18. }
  19. public func isIPv4() throws -> Bool {
  20. return try socket.isIPv4()
  21. }
  22. deinit {
  23. stop()
  24. }
  25. public func start(port: in_port_t = 8080, forceIPv4: Bool = false, priority: Int = DISPATCH_QUEUE_PRIORITY_BACKGROUND) throws {
  26. stop()
  27. self.socket = try Socket.tcpSocketForListen(port, forceIPv4: forceIPv4)
  28. self.running = true
  29. dispatch_async(dispatch_get_global_queue(priority, 0)) {
  30. while let socket = try? self.socket.acceptClientSocket() {
  31. dispatch_async(dispatch_get_global_queue(priority, 0), {
  32. self.sockets.insert(socket)
  33. self.handleConnection(socket)
  34. self.sockets.remove(socket)
  35. })
  36. }
  37. self.stop()
  38. self.running = false
  39. }
  40. }
  41. public func stop() {
  42. // Shutdown connected peers because they can live in 'keep-alive' or 'websocket' loops.
  43. for socket in self.sockets {
  44. socket.shutdwn()
  45. }
  46. self.sockets.removeAll(keepCapacity: true)
  47. socket.release()
  48. self.running = false
  49. }
  50. public func dispatch(request: HttpRequest) -> ([String: String], HttpRequest -> HttpResponse) {
  51. return ([:], { _ in HttpResponse.NotFound })
  52. }
  53. private func handleConnection(socket: Socket) {
  54. let parser = HttpParser()
  55. while let request = try? parser.readHttpRequest(socket) {
  56. let request = request
  57. request.address = try? socket.peername()
  58. let (params, handler) = self.dispatch(request)
  59. request.params = params
  60. let response = handler(request)
  61. var keepConnection = parser.supportsKeepAlive(request.headers)
  62. do {
  63. keepConnection = try self.respond(socket, response: response, keepAlive: keepConnection)
  64. } catch {
  65. print("Failed to send response: \(error)")
  66. break
  67. }
  68. if let session = response.socketSession() {
  69. session(socket)
  70. break
  71. }
  72. if !keepConnection { break }
  73. }
  74. socket.release()
  75. }
  76. private struct InnerWriteContext: HttpResponseBodyWriter {
  77. let socket: Socket
  78. func write(file: File) throws {
  79. try socket.writeFile(file)
  80. }
  81. func write(data: [UInt8]) throws {
  82. try write(ArraySlice(data))
  83. }
  84. func write(data: ArraySlice<UInt8>) throws {
  85. try socket.writeUInt8(data)
  86. }
  87. }
  88. private func respond(socket: Socket, response: HttpResponse, keepAlive: Bool) throws -> Bool {
  89. try socket.writeUTF8("HTTP/1.1 \(response.statusCode()) \(response.reasonPhrase())\r\n")
  90. let content = response.content()
  91. if content.length >= 0 {
  92. try socket.writeUTF8("Content-Length: \(content.length)\r\n")
  93. }
  94. if keepAlive && content.length != -1 {
  95. try socket.writeUTF8("Connection: keep-alive\r\n")
  96. }
  97. for (name, value) in response.headers() {
  98. try socket.writeUTF8("\(name): \(value)\r\n")
  99. }
  100. try socket.writeUTF8("\r\n")
  101. if let writeClosure = content.write {
  102. let context = InnerWriteContext(socket: socket)
  103. try writeClosure(context)
  104. }
  105. return keepAlive && content.length != -1;
  106. }
  107. }
  108. #if os(Linux)
  109. let DISPATCH_QUEUE_PRIORITY_BACKGROUND = 0
  110. private class dispatch_context {
  111. let block: ((Void) -> Void)
  112. init(_ block: ((Void) -> Void)) {
  113. self.block = block
  114. }
  115. }
  116. func dispatch_get_global_queue(queueId: Int, _ arg: Int) -> Int { return 0 }
  117. func dispatch_async(queueId: Int, _ block: ((Void) -> Void)) {
  118. let unmanagedDispatchContext = Unmanaged.passRetained(dispatch_context(block))
  119. let context = UnsafeMutablePointer<Void>(unmanagedDispatchContext.toOpaque())
  120. var pthread: pthread_t = 0
  121. pthread_create(&pthread, nil, { (context: UnsafeMutablePointer<Void>) -> UnsafeMutablePointer<Void> in
  122. let unmanaged = Unmanaged<dispatch_context>.fromOpaque(COpaquePointer(context))
  123. unmanaged.takeUnretainedValue().block()
  124. unmanaged.release()
  125. return context
  126. }, context)
  127. }
  128. #endif