main.swift 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import Foundation
  2. import NIO
  3. import NIOHTTP1
  4. struct JSONTestResponse: Encodable {
  5. let message = "Hello, World!"
  6. }
  7. enum Constants {
  8. static let httpVersion = HTTPVersion(major: 1, minor: 1)
  9. static let serverName = "SwiftNIO"
  10. static let plainTextResponse: StaticString = "Hello, World!"
  11. static let plainTextResponseLength = plainTextResponse.utf8CodeUnitCount
  12. static let plainTextResponseLengthString = String(plainTextResponseLength)
  13. static let jsonResponse = try! JSONEncoder().encode(JSONTestResponse())
  14. static let jsonResponseLength = try! JSONEncoder().encode(JSONTestResponse()).count
  15. static let jsonResponseLengthString = String(jsonResponseLength)
  16. }
  17. private final class HTTPHandler: ChannelInboundHandler {
  18. public typealias InboundIn = HTTPServerRequestPart
  19. public typealias OutboundOut = HTTPServerResponsePart
  20. let dateCache: RFC1123DateCache
  21. var plaintextBuffer: ByteBuffer
  22. var jsonBuffer: ByteBuffer
  23. init(channel: Channel) {
  24. let allocator = ByteBufferAllocator()
  25. self.plaintextBuffer = allocator.buffer(capacity: Constants.plainTextResponseLength)
  26. self.plaintextBuffer.writeStaticString(Constants.plainTextResponse)
  27. self.jsonBuffer = allocator.buffer(capacity: Constants.jsonResponseLength)
  28. self.jsonBuffer.writeBytes(Constants.jsonResponse)
  29. self.dateCache = .on(channel.eventLoop)
  30. }
  31. func channelRead(context: ChannelHandlerContext, data: NIOAny) {
  32. switch self.unwrapInboundIn(data) {
  33. case .head(let request):
  34. switch request.uri {
  35. case "/p":
  36. self.processPlaintext(context: context)
  37. case "/j":
  38. self.processJSON(context: context)
  39. default:
  40. _ = context.close()
  41. }
  42. case .body:
  43. break
  44. case .end:
  45. context.write(self.wrapOutboundOut(.end(nil)), promise: nil)
  46. }
  47. }
  48. func channelReadComplete(context: ChannelHandlerContext) {
  49. context.flush()
  50. context.fireChannelReadComplete()
  51. }
  52. private func processPlaintext(context: ChannelHandlerContext) {
  53. let responseHead = self.responseHead(contentType: "text/plain", contentLength: Constants.plainTextResponseLengthString)
  54. context.write(self.wrapOutboundOut(.head(responseHead)), promise: nil)
  55. context.write(self.wrapOutboundOut(.body(.byteBuffer(self.plaintextBuffer))), promise: nil)
  56. }
  57. private func processJSON(context: ChannelHandlerContext) {
  58. let responseHead = self.responseHead(contentType: "application/json", contentLength: Constants.jsonResponseLengthString)
  59. context.write(self.wrapOutboundOut(.head(responseHead)), promise: nil)
  60. context.write(self.wrapOutboundOut(.body(.byteBuffer(self.jsonBuffer))), promise: nil)
  61. }
  62. private func responseHead(contentType: String, contentLength: String) -> HTTPResponseHead {
  63. var headers = HTTPHeaders()
  64. headers.add(name: "content-type", value: contentType)
  65. headers.add(name: "content-length", value: contentLength)
  66. headers.add(name: "server", value: Constants.serverName)
  67. headers.add(name: "date", value: self.dateCache.currentTimestamp())
  68. return HTTPResponseHead(
  69. version: Constants.httpVersion,
  70. status: .ok,
  71. headers: headers
  72. )
  73. }
  74. }
  75. let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
  76. let bootstrap = ServerBootstrap(group: group)
  77. .serverChannelOption(ChannelOptions.backlog, value: 8192)
  78. .serverChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
  79. .childChannelInitializer { channel in
  80. channel.pipeline.configureHTTPServerPipeline(withPipeliningAssistance: false).flatMap {
  81. channel.pipeline.addHandler(HTTPHandler(channel: channel))
  82. }
  83. }
  84. .childChannelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
  85. .childChannelOption(ChannelOptions.maxMessagesPerRead, value: 16)
  86. defer {
  87. try! group.syncShutdownGracefully()
  88. }
  89. let channel = try bootstrap.bind(host: "0.0.0.0", port: 8080).wait()
  90. guard let localAddress = channel.localAddress else {
  91. fatalError("Address was unable to bind. Please check that the socket was not closed or that the address family was understood.")
  92. }
  93. try channel.closeFuture.wait()