Sfoglia il codice sorgente

Added .HTML case for .OK response code.
Fixed BODY read operation.
test.json and login.html resources are available for mac OS X target.
HttpRequest extended by urlParams field.

Damian Kołakowski 11 anni fa
parent
commit
64bca5ed60

+ 29 - 33
Common/DemoServer.swift

@@ -13,21 +13,24 @@ func demoServer(publicDir: String?) -> HttpServer {
     if let publicDir = publicDir {
         server["/resources/(.+)"] = HttpHandlers.directory(publicDir)
     }
+    server["/magic"] = { .OK(.HTML("You called: " + $0.url)) }
     server["/test"] = { request in
         var headersInfo = ""
         for (name, value) in request.headers {
             headersInfo += "\(name) : \(value)<br>"
         }
-        let response = "<html><body>Url: \(request.url)<br>Method: \(request.method)<br>\(headersInfo)</body></html>"
-        return .OK(.RAW(response))
+        var queryParamsInfo = ""
+        for (name, value) in request.urlParams {
+            queryParamsInfo += "\(name) : \(value)<br>"
+        }
+        return .OK(.HTML("<h3>Url:</h3> \(request.url)<h3>Method: \(request.method)</h3><h3>Headers:</h3>\(headersInfo)<h3>Query:</h3>\(queryParamsInfo)"))
     }
     server["/params/(.+)/(.+)"] = { request in
         var capturedGroups = ""
         for (index, group) in enumerate(request.capturedUrlGroups) {
             capturedGroups += "Expression group \(index) : \(group)<br>"
         }
-        let response = "<html><body>Url: \(request.url)<br>Method: \(request.method)<br>\(capturedGroups)</body></html>"
-        return .OK(.RAW(response))
+        return .OK(.HTML("Url: \(request.url)<br>Method: \(request.method)<br>\(capturedGroups)"))
     }
     server["/json"] = { request in
         return .OK(.JSON(["posts" : [[ "id" : 1, "message" : "hello world"],[ "id" : 2, "message" : "sample message"]], "new_updates" : false]))
@@ -41,47 +44,40 @@ func demoServer(publicDir: String?) -> HttpServer {
         return .OK(.RAW(longResponse))
     }
     server["/demo"] = { request in
-        return .OK(.RAW("<html><body><center><h2>Hello Swift</h2>" +
+        return .OK(.HTML("<center><h2>Hello Swift</h2>" +
             "<img src=\"https://devimages.apple.com.edgekey.net/swift/images/swift-hero_2x.png\"/><br>" +
-            "</center></body></html>"))
+            "</center>"))
     }
     server["/login"] = { request in
-        println(">> request method:\(request.method.uppercaseString)")
-        var method = request.method.uppercaseString
-        if method == "GET" {
-            if let rootDir = publicDir{
-                if let html = String(contentsOfFile:"\(rootDir)/login.html", encoding: NSUTF8StringEncoding, error: nil){
-                    return .OK(.RAW(html))
-                }else{
-                    return .NotFound
-                }
-            }
-        }else if method == "POST"{
-            println(">> post data: \(NSString(data:request.body!,encoding:NSUTF8StringEncoding))")
-            var html = "<html><body>"
-            let body = NSString(data: request.body!, encoding: NSUTF8StringEncoding)
-            if let parameters = body?.componentsSeparatedByString("&"){
-                if let email = parameters[0] as? String{
-                    html += "\(email)<br>"
-                }
-                if let password = parameters[1] as? String{
-                    html += "\(password)"
+        switch request.method.uppercaseString {
+            case "GET":
+                if let rootDir = publicDir {
+                    if let html = String(contentsOfFile:"\(rootDir)/login.html", encoding: NSUTF8StringEncoding, error: nil){
+                        return .OK(.RAW(html))
+                    } else {
+                        return .NotFound
+                    }
                 }
+                break;
+            case "POST":
+                if let body = request.body {
+                    return .OK(.HTML(body))
+                } else {
+                    return .OK(.HTML("No POST params."))
             }
-            html += "</body></html>"
-            return .OK(.RAW(html))
-            //return .MovedPermanently("http://github.com")
+            default:
+                return .NotFound
         }
-        
         return .NotFound
     }
     server["/"] = { request in
-        var listPage = "<html><body>Available services:<br><ul>"
+        var listPage = "Available services:<br><ul>"
+        enumerate(server.routes())
         for item in server.routes() {
             listPage += "<li><a href=\"\(item)\">\(item)</a></li>"
         }
-        listPage += "</ul></body></html>"
-        return .OK(.RAW(listPage))
+        listPage += "</ul>"
+        return .OK(.HTML(listPage))
     }
     return server
 }

+ 43 - 26
Common/HttpParser.swift

@@ -23,22 +23,51 @@ class HttpParser {
             }
             let method = statusTokens[0]
             let path = statusTokens[1]
+            let urlParams = extractUrlParams(path)
+            // TODO extract query parameters
             if let headers = nextHeaders(socket, error: error) {
-                var requestBody = ""
-                while let line = nextLine(socket, error: error) {
-                    if line.isEmpty {
-                        break
-                    }
-                    requestBody += line
+                // TODO detect content-type and handle:
+                // 'application/x-www-form-urlencoded' -> Dictionary
+                // 'multipart' -> Dictionary
+                if let contentSize = headers["content-length"]?.toInt() {
+                    let body = nextBody(socket, size: contentSize, error: error)
+                    return HttpRequest(url: path, urlParams: urlParams, method: method, headers: headers, body: body, capturedUrlGroups: [])
                 }
-                println(requestBody)
-                let body = requestBody.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
-                return HttpRequest(url: path, method: method, headers: headers, body: body, capturedUrlGroups: [])
+                return HttpRequest(url: path, urlParams: urlParams, method: method, headers: headers, body: nil, capturedUrlGroups: [])
             }
         }
         return nil
     }
     
+    private func extractUrlParams(url: String) -> [(String, String)] {
+        var result = [(String, String)]()
+        let tokens = url.componentsSeparatedByString("?")
+        if tokens.count >= 2 {
+            for pair in tokens[1].componentsSeparatedByString("&") {
+                let keyAndValue = pair.componentsSeparatedByString("=")
+                if keyAndValue.count >= 2 {
+                    result.append((keyAndValue[0], keyAndValue[1]))
+                }
+            }
+        }
+        return result
+    }
+    
+    private func nextBody(socket: CInt, size: Int , error:NSErrorPointer) -> String? {
+        var body = ""
+        var counter = 0;
+        while ( counter < size ) {
+            let c = nextUInt8(socket)
+            if ( c < 0 ) {
+                if error != nil { error.memory = HttpParser.err("IO error while reading body") }
+                return nil
+            }
+            body.append(UnicodeScalar(c))
+            counter++;
+        }
+        return body
+    }
+    
     private func nextHeaders(socket: CInt, error:NSErrorPointer) -> Dictionary<String, String>? {
         var headers = Dictionary<String, String>()
         while let headerLine = nextLine(socket, error: error) {
@@ -51,7 +80,7 @@ class HttpParser {
                 // "Each header field consists of a name followed by a colon (":") and the field value. Field names are case-insensitive."
                 // We can keep lower case version.
                 let headerName = headerTokens[0].lowercaseString
-                let headerValue = headerTokens[1]
+                let headerValue = headerTokens[1].stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
                 if ( !headerName.isEmpty && !headerValue.isEmpty ) {
                     headers.updateValue(headerValue, forKey: headerName)
                 }
@@ -60,23 +89,11 @@ class HttpParser {
         return nil
     }
 
-    var recvBuffer = [UInt8](count: 1024, repeatedValue: 0)
-    var recvBufferSize: Int = 0
-    var recvBufferOffset: Int = 0
-    
     private func nextUInt8(socket: CInt) -> Int {
-        if ( recvBufferSize == 0 || recvBufferOffset == recvBuffer.count ) {
-            recvBufferOffset = 0
-            recvBufferSize = recv(socket, &recvBuffer, UInt(recvBuffer.count), 0)
-            if ( recvBufferSize <= 0 ) { return recvBufferSize }
-            if recvBufferSize < recvBuffer.count
-            {
-                recvBuffer[recvBufferSize] = 0
-            }
-        }
-        let returnValue = recvBuffer[recvBufferOffset]
-        recvBufferOffset++
-        return Int(returnValue)
+        var buffer = [UInt8](count: 1, repeatedValue: 0);
+        let next = recv(socket, &buffer, UInt(buffer.count), 0)
+        if next <= 0 { return next }
+        return Int(buffer[0])
     }
     
     private func nextLine(socket: CInt, error:NSErrorPointer) -> String? {

+ 3 - 2
Common/HttpRequest.swift

@@ -8,10 +8,11 @@
 
 import Foundation
 
-struct HttpRequest {
+struct HttpRequest {    
     let url: String
+    let urlParams: [(String, String)] // http://stackoverflow.com/questions/1746507/authoritative-position-of-duplicate-http-get-query-keys
     let method: String
     let headers: Dictionary<String, String>
-	let body: NSData?
+	let body: String?
     var capturedUrlGroups: [String]
 }

+ 3 - 0
Common/HttpResponse.swift

@@ -14,6 +14,7 @@ enum HttpResponseBody {
     case XML(AnyObject)
     case PLIST(AnyObject)
     case RAW(String)
+    case HTML(String)
     
     func data() -> String? {
         switch self {
@@ -40,6 +41,8 @@ enum HttpResponseBody {
             return "Invalid object to serialise."
         case .RAW(let data):
             return data
+        case .HTML(let body):
+            return "<html><body>\(body)</body></html>"
         }
     }
 }

+ 2 - 28
Common/HttpServer.swift

@@ -29,33 +29,7 @@ class HttpServer
             }
         }
     }
-    
-//    Uncommenting this will cause following compilation errors:
-//
-//      Cannot invoke 'subscript' with an argument list of type '($T5, Builtin.RawPointer)'
-//      Cannot invoke 'subscript' with an argument list of type '($T5, Builtin.RawPointer)'
-//
-//    Swift stopped to support subscripts with multiple outputs.
-//
-//    subscript (asdasd: String) -> String {
-//        get {
-//            return asdasd
-//        }
-//        set ( directoryPath ) {
-//            if let regex = NSRegularExpression(pattern: asdasd, options: expressionOptions, error: nil) {
-//                handlers.append(expression: regex, handler: { request in
-//                    let result = regex.firstMatchInString(request.url, options: self.matchingOptions, range: NSMakeRange(0, request.url.lengthOfBytesUsingEncoding(NSASCIIStringEncoding)))
-//                    let nsPath: NSString = request.url
-//                    let filesPath = directoryPath.stringByExpandingTildeInPath.stringByAppendingPathComponent(nsPath.substringWithRange(result!.rangeAtIndex(1)))
-//                    if let fileBody = String(contentsOfFile: filesPath, encoding: NSUTF8StringEncoding, error: nil) {
-//                        return HttpResponse.OK(.RAW(fileBody))
-//                    }
-//                    return HttpResponse.NotFound
-//                })
-//            }
-//        }
-//    }
-    
+        
     func routes() -> Array<String> {
         var results = [String]()
         for (expression,_) in handlers { results.append(expression.pattern) }
@@ -74,7 +48,7 @@ class HttpServer
                             let keepAlive = parser.supportsKeepAlive(request.headers)
                             if let (expression, handler) = self.findHandler(request.url) {
                                 let capturedUrlsGroups = self.captureExpressionGroups(expression, value: request.url)
-                                let updatedRequest = HttpRequest(url: request.url, method: request.method, headers: request.headers, body: request.body, capturedUrlGroups: capturedUrlsGroups)
+                                let updatedRequest = HttpRequest(url: request.url, urlParams: request.urlParams, method: request.method, headers: request.headers, body: request.body, capturedUrlGroups: capturedUrlsGroups)
                                 HttpServer.writeResponse(socket, response: handler(updatedRequest), keepAlive: keepAlive)
                             } else {
                                 HttpServer.writeResponse(socket, response: HttpResponse.NotFound, keepAlive: keepAlive)

+ 4 - 2
Swifter.xcodeproj/project.pbxproj

@@ -9,6 +9,7 @@
 /* Begin PBXBuildFile section */
 		7C6A510E1A149859004924B5 /* ActiveRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6A510D1A149859004924B5 /* ActiveRecord.swift */; };
 		7C6A510F1A149859004924B5 /* ActiveRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C6A510D1A149859004924B5 /* ActiveRecord.swift */; };
+		7C71C5B01A1D52F800682BF0 /* login.html in CopyFiles */ = {isa = PBXBuildFile; fileRef = 98630C061A1C9A9D00478D08 /* login.html */; };
 		7C839B7419422CFF003A6950 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C839B7319422CFF003A6950 /* AppDelegate.swift */; };
 		7C839B7619422CFF003A6950 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C839B7519422CFF003A6950 /* ViewController.swift */; };
 		7C839B7919422CFF003A6950 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7C839B7719422CFF003A6950 /* Main.storyboard */; };
@@ -37,13 +38,14 @@
 /* Begin PBXCopyFilesBuildPhase section */
 		7CA4813919A2EA8D0030B30D /* CopyFiles */ = {
 			isa = PBXCopyFilesBuildPhase;
-			buildActionMask = 8;
+			buildActionMask = 12;
 			dstPath = "";
 			dstSubfolderSpec = 7;
 			files = (
+				7C71C5B01A1D52F800682BF0 /* login.html in CopyFiles */,
 				7CA4815919A2EF560030B30D /* test.json in CopyFiles */,
 			);
-			runOnlyForDeploymentPostprocessing = 1;
+			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXCopyFilesBuildPhase section */
 

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


+ 163 - 35
Swifter.xcodeproj/xcuserdata/damiankolakowski.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

@@ -200,11 +200,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpResponse.swift"
-            timestampString = "430110038.828632"
+            timestampString = "438133493.46376"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "35"
-            endingLineNumber = "35"
+            startingLineNumber = "36"
+            endingLineNumber = "36"
             landmarkName = "data()"
             landmarkType = "5">
             <Locations>
@@ -246,11 +246,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "437665731.313686"
+            timestampString = "438134345.357079"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "67"
-            endingLineNumber = "67"
+            startingLineNumber = "41"
+            endingLineNumber = "41"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -262,11 +262,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "437665731.313686"
+            timestampString = "438134345.357079"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "69"
-            endingLineNumber = "69"
+            startingLineNumber = "43"
+            endingLineNumber = "43"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -278,11 +278,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "437665731.313686"
+            timestampString = "438134345.357079"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "71"
-            endingLineNumber = "71"
+            startingLineNumber = "45"
+            endingLineNumber = "45"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -294,11 +294,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "437665731.313686"
+            timestampString = "438134345.357079"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "73"
-            endingLineNumber = "73"
+            startingLineNumber = "47"
+            endingLineNumber = "47"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -310,11 +310,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "437665731.313686"
+            timestampString = "438134345.357079"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "75"
-            endingLineNumber = "75"
+            startingLineNumber = "49"
+            endingLineNumber = "49"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -326,11 +326,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "437675481.833013"
+            timestampString = "438134345.357079"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "79"
-            endingLineNumber = "79"
+            startingLineNumber = "53"
+            endingLineNumber = "53"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -342,11 +342,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "437675481.833013"
+            timestampString = "438134345.357079"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "80"
-            endingLineNumber = "80"
+            startingLineNumber = "54"
+            endingLineNumber = "54"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -363,8 +363,8 @@
             endingColumnNumber = "9223372036854775807"
             startingLineNumber = "45"
             endingLineNumber = "45"
-            landmarkName = "commit(_:)"
-            landmarkType = "5">
+            landmarkName = "Person"
+            landmarkType = "3">
          </BreakpointContent>
       </BreakpointProxy>
       <BreakpointProxy
@@ -390,11 +390,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "437675622.074193"
+            timestampString = "438134345.357079"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "101"
-            endingLineNumber = "101"
+            startingLineNumber = "75"
+            endingLineNumber = "75"
             landmarkName = "captureExpressionGroups(_:value:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -406,11 +406,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/DemoServer.swift"
-            timestampString = "437682950.226404"
+            timestampString = "438134997.779982"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "46"
-            endingLineNumber = "46"
+            startingLineNumber = "49"
+            endingLineNumber = "49"
             landmarkName = "demoServer(_:)"
             landmarkType = "7">
          </BreakpointContent>
@@ -422,14 +422,142 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "437682692.747736"
+            timestampString = "438134345.357079"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "76"
-            endingLineNumber = "76"
+            startingLineNumber = "50"
+            endingLineNumber = "50"
             landmarkName = "start(listenPort:error:)"
             landmarkType = "5">
          </BreakpointContent>
       </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/DemoServer.swift"
+            timestampString = "438134997.779982"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "51"
+            endingLineNumber = "51"
+            landmarkName = "demoServer(_:)"
+            landmarkType = "7">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/DemoServer.swift"
+            timestampString = "438134997.779982"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "63"
+            endingLineNumber = "63"
+            landmarkName = "demoServer(_:)"
+            landmarkType = "7">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpParser.swift"
+            timestampString = "438130358.291299"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "17"
+            endingLineNumber = "17"
+            landmarkName = "nextHttpRequest(_:error:)"
+            landmarkType = "5">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpParser.swift"
+            timestampString = "438134345.357079"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "32"
+            endingLineNumber = "32"
+            landmarkName = "nextHttpRequest(_:error:)"
+            landmarkType = "5">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpParser.swift"
+            timestampString = "438134345.357079"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "33"
+            endingLineNumber = "33"
+            landmarkName = "nextHttpRequest(_:error:)"
+            landmarkType = "5">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpParser.swift"
+            timestampString = "438134345.357079"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "34"
+            endingLineNumber = "34"
+            landmarkName = "nextHttpRequest(_:error:)"
+            landmarkType = "5">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpParser.swift"
+            timestampString = "438134345.357079"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "37"
+            endingLineNumber = "37"
+            landmarkName = "nextHttpRequest(_:error:)"
+            landmarkType = "5">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpParser.swift"
+            timestampString = "438134345.357079"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "36"
+            endingLineNumber = "36"
+            landmarkName = "nextHttpRequest(_:error:)"
+            landmarkType = "5">
+         </BreakpointContent>
+      </BreakpointProxy>
    </Breakpoints>
 </Bucket>

+ 1 - 3
SwifterOSX/main.swift

@@ -8,12 +8,10 @@
 
 import Foundation
 
-let server = demoServer("~/")
+let server = demoServer(NSBundle.mainBundle().resourcePath)
 
 var error: NSError?
 
-let person = Person()
-
 if !server.start(error: &error) {
     println("Server start error: \(error)")
 } else {