Kaynağa Gözat

Added one more example handlers to simulate basic files browser.
Query parameters are url decode before passing it to handler.
Swifter presents itself with "Server" header.

Damian Kołakowski 11 yıl önce
ebeveyn
işleme
6ae3e7d4c8

+ 1 - 0
Common/DemoServer.swift

@@ -13,6 +13,7 @@ func demoServer(publicDir: String?) -> HttpServer {
     if let publicDir = publicDir {
         server["/resources/(.+)"] = HttpHandlers.directory(publicDir)
     }
+    server["/files(.+)"] = HttpHandlers.directoryBrowser("~/")
     server["/magic"] = { .OK(.HTML("You asked for " + $0.url)) }
     server["/test"] = { request in
         var headersInfo = ""

+ 25 - 0
Common/HttpHandlers.swift

@@ -21,4 +21,29 @@ class HttpHandlers {
             return HttpResponse.NotFound
         }
     }
+
+    class func directoryBrowser(dir: String) -> ( HttpRequest -> HttpResponse ) {
+        return { request in
+            if let pathFromUrl = request.capturedUrlGroups.first {
+                let filePath = dir.stringByExpandingTildeInPath.stringByAppendingPathComponent(pathFromUrl)
+                let fileManager = NSFileManager.defaultManager()
+                var isDir: ObjCBool = false;
+                if ( fileManager.fileExistsAtPath(filePath, isDirectory: &isDir) ) {
+                    if ( isDir ) {
+                        if let files = fileManager.contentsOfDirectoryAtPath(filePath, error: nil) {
+                            var response = "<h3>\(filePath)</h3></br><table>"
+                            response += join("", map(files, { "<tr><td><a href=\"\(request.url)/\($0)\">\($0)</a></td></tr>"}))
+                            response += "</table>"
+                            return HttpResponse.OK(.HTML(response))
+                        }
+                    } else {
+                        if let fileBody = NSData(contentsOfFile: filePath) {
+                            return HttpResponse.RAW(200, fileBody)
+                        }
+                    }
+                }
+            }
+            return HttpResponse.NotFound
+        }
+    }
 }

+ 6 - 1
Common/HttpParser.swift

@@ -43,7 +43,12 @@ class HttpParser {
         if let query = split(url, { $0 == "?" }).last {
             return map(split(query, { $0 == "&" }), { (param:String) -> (String, String) in
                 let tokens = split(param, { $0 == "=" })
-                return tokens.count >= 2 ? (tokens.first!, tokens.last!) : ("", "")
+                if tokens.count >= 2 {
+                    let key = tokens[0].stringByRemovingPercentEncoding
+                    let value = tokens[1].stringByRemovingPercentEncoding
+                    if key != nil && value != nil { return (key!, value!) }
+                }
+                return ("","")
             })
         }
         return []

+ 6 - 3
Common/HttpResponse.swift

@@ -85,11 +85,14 @@ enum HttpResponse {
         }
     }
     
-    func headers() -> Dictionary<String, String> {
+    func headers() -> [String: String] {
+        var headers = [String:String]()
+        headers["Server"] = "Swifter"
         switch self {
-        case .MovedPermanently(let location) : return [ "Location" : location ]
-        default: return Dictionary()
+        case .MovedPermanently(let location) : headers["Location"] = location
+        default:[];
         }
+        return headers
     }
     
     func body() -> NSData? {

+ 15 - 13
Common/HttpServer.swift

@@ -22,7 +22,7 @@ class HttpServer
             return nil
         }
         set ( newValue ) {
-            if let regex: NSRegularExpression = NSRegularExpression(pattern: path, options: expressionOptions, error: nil) {
+            if let regex = NSRegularExpression(pattern: path, options: expressionOptions, error: nil) {
                 if let newHandler = newValue {
                     handlers.append(expression: regex, handler: newHandler)
                 }
@@ -30,13 +30,9 @@ class HttpServer
         }
     }
         
-    func routes() -> Array<String> {
-        var results = [String]()
-        for (expression,_) in handlers { results.append(expression.pattern) }
-        return results
-    }
+    func routes() -> [String] { return map(handlers, { $0.0.pattern }) }
     
-    func start(listenPort: in_port_t = 8080, error:NSErrorPointer = nil) -> Bool {
+    func start(listenPort: in_port_t = 8080, error: NSErrorPointer = nil) -> Bool {
         releaseAcceptSocket()
         if let socket = Socket.tcpForListen(port: listenPort, error: error) {
             acceptSocket = socket
@@ -56,32 +52,38 @@ class HttpServer
                             if !keepAlive { break }
                         }
                         Socket.release(socket)
-                    });
+                    })
                 }
                 self.releaseAcceptSocket()
-            });
+            })
             return true
         }
         return false
     }
     
     func findHandler(url:String) -> (NSRegularExpression, Handler)? {
-        return filter(self.handlers, { (expression: NSRegularExpression, handler) -> Bool in
-            return expression.numberOfMatchesInString(url, options: self.matchingOptions, range: NSMakeRange(0, url.lengthOfBytesUsingEncoding(NSASCIIStringEncoding))) > 0
+        return filter(self.handlers, {
+            $0.0.numberOfMatchesInString(url, options: self.matchingOptions, range: HttpServer.asciiRange(url)) > 0
         }).first
     }
     
     func captureExpressionGroups(expression: NSRegularExpression, value: String) -> [String] {
         var capturedGroups = [String]()
-        if let result = expression.firstMatchInString(value, options: matchingOptions, range: NSMakeRange(0, value.lengthOfBytesUsingEncoding(NSASCIIStringEncoding))) {
+        if let result = expression.firstMatchInString(value, options: matchingOptions, range: HttpServer.asciiRange(value)) {
             let nsValue: NSString = value
             for var i = 1 ; i < result.numberOfRanges ; ++i {
-                capturedGroups.append(nsValue.substringWithRange(result.rangeAtIndex(i)))
+                if let group = nsValue.substringWithRange(result.rangeAtIndex(i)).stringByRemovingPercentEncoding {
+                    capturedGroups.append(group)
+                }
             }
         }
         return capturedGroups
     }
     
+    class func asciiRange(value: String) -> NSRange {
+        return NSMakeRange(0, value.lengthOfBytesUsingEncoding(NSASCIIStringEncoding))
+    }
+    
     class func writeResponse(socket: CInt, response: HttpResponse, keepAlive: Bool) {
         Socket.writeStringUTF8(socket, string: "HTTP/1.1 \(response.statusCode()) \(response.reasonPhrase())\r\n")
         if let body = response.body() {

BIN
Swifter.xcodeproj/project.xcworkspace/xcuserdata/damiankolakowski.xcuserdatad/UserInterfaceState.xcuserstate


+ 97 - 53
Swifter.xcodeproj/xcuserdata/damiankolakowski.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

@@ -246,11 +246,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "438134345.357079"
+            timestampString = "438266226.339419"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "41"
-            endingLineNumber = "41"
+            startingLineNumber = "39"
+            endingLineNumber = "39"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -262,11 +262,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "438134345.357079"
+            timestampString = "438266226.339419"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "43"
-            endingLineNumber = "43"
+            startingLineNumber = "41"
+            endingLineNumber = "41"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -278,11 +278,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "438134345.357079"
+            timestampString = "438266226.339419"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "45"
-            endingLineNumber = "45"
+            startingLineNumber = "43"
+            endingLineNumber = "43"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -294,11 +294,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "438134345.357079"
+            timestampString = "438266226.339419"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "47"
-            endingLineNumber = "47"
+            startingLineNumber = "45"
+            endingLineNumber = "45"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -310,7 +310,7 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "438134345.357079"
+            timestampString = "438266226.339419"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
             startingLineNumber = "49"
@@ -326,27 +326,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "438134345.357079"
-            startingColumnNumber = "9223372036854775807"
-            endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "53"
-            endingLineNumber = "53"
-            landmarkName = "start(listenPort:error:)"
-            landmarkType = "5">
-         </BreakpointContent>
-      </BreakpointProxy>
-      <BreakpointProxy
-         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
-         <BreakpointContent
-            shouldBeEnabled = "No"
-            ignoreCount = "0"
-            continueAfterRunningActions = "No"
-            filePath = "Common/HttpServer.swift"
-            timestampString = "438134345.357079"
+            timestampString = "438266226.339419"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "54"
-            endingLineNumber = "54"
+            startingLineNumber = "50"
+            endingLineNumber = "50"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -390,11 +374,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "438134345.357079"
+            timestampString = "438292568.591795"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "75"
-            endingLineNumber = "75"
+            startingLineNumber = "70"
+            endingLineNumber = "70"
             landmarkName = "captureExpressionGroups(_:value:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -406,11 +390,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/DemoServer.swift"
-            timestampString = "438138106.626601"
+            timestampString = "438294105.63842"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "53"
-            endingLineNumber = "53"
+            startingLineNumber = "54"
+            endingLineNumber = "54"
             landmarkName = "demoServer(_:)"
             landmarkType = "7">
          </BreakpointContent>
@@ -422,11 +406,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "438134345.357079"
+            timestampString = "438266226.339419"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "50"
-            endingLineNumber = "50"
+            startingLineNumber = "46"
+            endingLineNumber = "46"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -438,11 +422,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/DemoServer.swift"
-            timestampString = "438138106.626601"
+            timestampString = "438294105.63842"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "55"
-            endingLineNumber = "55"
+            startingLineNumber = "56"
+            endingLineNumber = "56"
             landmarkName = "demoServer(_:)"
             landmarkType = "7">
          </BreakpointContent>
@@ -454,11 +438,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/DemoServer.swift"
-            timestampString = "438138106.626601"
+            timestampString = "438294105.63842"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "67"
-            endingLineNumber = "67"
+            startingLineNumber = "68"
+            endingLineNumber = "68"
             landmarkName = "demoServer(_:)"
             landmarkType = "7">
          </BreakpointContent>
@@ -612,13 +596,13 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "438247447.382034"
+            timestampString = "438294105.63842"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
             startingLineNumber = "86"
             endingLineNumber = "86"
-            landmarkName = "writeResponse(_:response:keepAlive:)"
-            landmarkType = "5">
+            landmarkName = "HttpServer"
+            landmarkType = "3">
          </BreakpointContent>
       </BreakpointProxy>
       <BreakpointProxy
@@ -628,7 +612,7 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "438249249.036323"
+            timestampString = "438294105.63842"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
             startingLineNumber = "87"
@@ -664,8 +648,68 @@
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
             startingLineNumber = "55"
-            endingLineNumber = "55"
-            landmarkName = "writeStringUTF8(_:string:error:)"
+            endingLineNumber = "55">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpHandlers.swift"
+            timestampString = "438294169.275278"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "27"
+            endingLineNumber = "27">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpHandlers.swift"
+            timestampString = "438295102.201212"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "39"
+            endingLineNumber = "39"
+            landmarkName = "directoryBrowser(_:)"
+            landmarkType = "5">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpHandlers.swift"
+            timestampString = "438295103.268347"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "40"
+            endingLineNumber = "40"
+            landmarkName = "directoryBrowser(_:)"
+            landmarkType = "5">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpHandlers.swift"
+            timestampString = "438295116.116921"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "28"
+            endingLineNumber = "28"
+            landmarkName = "directoryBrowser(_:)"
             landmarkType = "5">
          </BreakpointContent>
       </BreakpointProxy>