ソースを参照

Merge pull request #2 from yawaramin/master

Use discriminated union for HTTP response; and check for keep-alive once per loop
Damian Kołakowski 12 年 前
コミット
2b5bdd9d3f
2 ファイル変更54 行追加27 行削除
  1. 12 9
      Swifter/AppDelegate.swift
  2. 42 18
      Swifter/HttpServer.swift

+ 12 - 9
Swifter/AppDelegate.swift

@@ -17,26 +17,29 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
     
     func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
         
-        server["/"] = { () -> (Int, String) in
-            return (HttpServer.Statuses.OK, "<html><body>Hello Swift</body></html>")
+        server["/"] = {
+            return .OK("<html><body>Hello Swift</body></html>")
         }
         
-        server["/hello"] = { () -> (Int, String) in
-            return (HttpServer.Statuses.OK, "<html><body>Hello !</body></html>")
+        server["/hello"] = {
+            return .OK("<html><body>Hello !</body></html>")
         }
         
-        server["/long"] = { () -> (Int, String) in
+        server["/long"] = {
             var longResponse = ""
             for k in 0..1000 {
                 longResponse += "(\(k)),->"
             }
-            return (HttpServer.Statuses.OK, longResponse)
+            return .OK(longResponse)
         }
         
-        server["/demo"] = { () -> (Int, String) in
-            return (HttpServer.Statuses.OK, "<html><body><center><h2>Hello Swift</h2>" +
+        server["/demo"] = {
+            let demoPage =
+                "<html><body><center><h2>Hello Swift</h2>" +
                 "<img src=\"https://devimages.apple.com.edgekey.net/swift/images/swift-hero_2x.png\"/><br>" +
-                            "<h4>\(UIDevice().name), \(UIDevice().systemVersion)</h4></center><iframe src=\"/demo2\"></iframe><iframe src=\"/hello\"></iframe></body></html>")
+                "<h4>\(UIDevice().name), \(UIDevice().systemVersion)</h4></center>" +
+                "<iframe src=\"/demo2\"></iframe><iframe src=\"/hello\"></iframe></body></html>"
+            return .OK(demoPage)
         }
         
         let (result, error) = server.start(8080)

+ 42 - 18
Swifter/HttpServer.swift

@@ -7,19 +7,38 @@
 
 import Foundation
 
-/* HTTP server */
+enum ResponseStatus {
+    case OK(String)
+    case NotFound
+
+    func numericValue() {
+        switch self {
+            case .OK(_):
+                return 200
+            case .NotFound:
+                return 404
+        }
+    }
+
+    func textValue() {
+        switch self {
+            case .OK(let text):
+                return text
+            case .NotFound:
+                return "Not found"
+        }
+    }
+}
 
+typealias Handler = Void -> ResponseStatus
+
+/* HTTP server */
 class HttpServer
 {
-    enum Statuses {
-        static let OK = 200
-        static let NOT_FOUND = 404
-    }
-    
-    var handlers: Dictionary<String, (Void -> (Int, String))> = Dictionary()
+    var handlers = Dictionary<String, Handler>()
     var acceptSocket: CInt = -1
     
-    subscript (path: String) -> ((Void -> (Int, String))) {
+    subscript (path: String) -> Handler {
         get {
             return handlers[path]!
         }
@@ -47,27 +66,32 @@ class HttpServer
                 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), { () -> Void in
                     let parser = HttpParser()
                     while let (path, headers) = parser.parseHttpHeader(socket) {
+                        let keepAlive = parser.supportsKeepAlive(headers)
+
                         if let handler = self.handlers[path] {
-                            let (status, response) = handler()
-                            Socket.writeStringUTF8(socket, string: "HTTP/1.1 \(status)\r\n")
-                            let nsdata = response.bridgeToObjectiveC().dataUsingEncoding(NSUTF8StringEncoding)
+                            let responseStatus = handler()
+                            let responseText = responseStatus.textValue()
+                            let nsdata =
+                                responseText
+                                    .bridgeToObjectiveC()
+                                    .dataUsingEncoding(NSUTF8StringEncoding)
+
+                            Socket.writeStringUTF8(socket, string: "HTTP/1.1 \(responseStatus.numericValue())\r\n")
                             Socket.writeStringUTF8(socket, string: "Content-Length: \(nsdata.length)\r\n")
-                            if parser.supportsKeepAlive(headers) {
+                            if keepAlive {
                                 Socket.writeStringUTF8(socket, string: "Connection: keep-alive\r\n")
                             }
                             Socket.writeStringUTF8(socket, string: "\r\n")
-                            Socket.writeStringUTF8(socket, string: response)
+                            Socket.writeStringUTF8(socket, string: responseText)
                         } else {
-                            Socket.writeStringUTF8(socket, string: "HTTP/1.1 \(Statuses.NOT_FOUND)\r\n")
+                            Socket.writeStringUTF8(socket, string: "HTTP/1.1 \(ResponseStatus.NotFound.numericValue())\r\n")
                             Socket.writeStringUTF8(socket, string: "Content-Length: 0\r\n")
-                            if parser.supportsKeepAlive(headers) {
+                            if keepAlive {
                                 Socket.writeStringUTF8(socket, string: "Connection: keep-alive\r\n")
                             }
                             Socket.writeStringUTF8(socket, string: "\r\n")
                         }
-                        if !parser.supportsKeepAlive(headers) {
-                            break
-                        }
+                        if !keepAlive { break }
                     }
                     Socket.release(socket)
                 });