Browse Source

The value of "Content-Type" header is automatically set for basic response ( .JSON, .XML, .PLST ).
.RAW response allows to modify all fields of the HTTP response (status code, status phrase, headers and body).

Damian Kołakowski 10 năm trước cách đây
mục cha
commit
2f45bc8fff

+ 4 - 1
Common/DemoServer.swift

@@ -53,7 +53,7 @@ func demoServer(publicDir: String?) -> HttpServer {
             case "GET":
                 if let rootDir = publicDir {
                     if let html = NSData(contentsOfFile:"\(rootDir)/login.html") {
-                        return .RAW(200, html)
+                        return HttpResponse.RAW(200, "OK", nil, html)
                     } else {
                         return .NotFound
                     }
@@ -70,6 +70,9 @@ func demoServer(publicDir: String?) -> HttpServer {
         }
         return .NotFound
     }
+    server["/raw"] = { request in
+        return HttpResponse.RAW(200, "OK", ["XXX-Custom-Header": "value"], "Sample Response".dataUsingEncoding(NSUTF8StringEncoding)!)
+    }
     server["/"] = { request in
         var listPage = "Available services:<br><ul>"
         for item in server.routes() {

+ 2 - 2
Common/HttpHandlers.swift

@@ -13,7 +13,7 @@ public class HttpHandlers {
             if let localPath = request.capturedUrlGroups.first {
                 let filesPath = dir.stringByExpandingTildeInPath.stringByAppendingPathComponent(localPath)
                 if let fileBody = NSData(contentsOfFile: filesPath) {
-                    return HttpResponse.RAW(200, fileBody)
+                    return HttpResponse.RAW(200, "OK", nil, fileBody)
                 }
             }
             return HttpResponse.NotFound
@@ -39,7 +39,7 @@ public class HttpHandlers {
                         }
                     } else {
                         if let fileBody = NSData(contentsOfFile: filePath) {
-                            return HttpResponse.RAW(200, fileBody)
+                            return HttpResponse.RAW(200, "OK", nil, fileBody)
                         }
                     }
                 }

+ 38 - 29
Common/HttpResponse.swift

@@ -12,41 +12,41 @@ public enum HttpResponseBody {
     case XML(AnyObject)
     case PLIST(AnyObject)
     case HTML(String)
-    case RAW(String)
+    case STRING(String)
     
-    func data() -> (content: String?, contentType: String?) {
+    func data() -> String? {
         switch self {
         case .JSON(let object):
             if NSJSONSerialization.isValidJSONObject(object) {
                 do {
                     let json = try NSJSONSerialization.dataWithJSONObject(object, options: NSJSONWritingOptions.PrettyPrinted)
                     if let nsString = NSString(data: json, encoding: NSUTF8StringEncoding) {
-                        return (nsString as String, "application/json")
+                        return nsString as String
                     }
                 } catch let serializationError as NSError {
-                    return ("Serialisation error: \(serializationError)", nil)
+                    return "Serialisation error: \(serializationError)"
                 }
             }
-            return ("Invalid object to serialise.", nil)
+            return "Invalid object to serialise."
         case .XML(_):
-            return ("XML serialization not supported.", nil)
+            return "XML serialization not supported."
         case .PLIST(let object):
             let format = NSPropertyListFormat.XMLFormat_v1_0
             if NSPropertyListSerialization.propertyList(object, isValidForFormat: format) {
                 do {
                     let plist = try NSPropertyListSerialization.dataWithPropertyList(object, format: format, options: 0)
                     if let nsString = NSString(data: plist, encoding: NSUTF8StringEncoding) {
-                        return (nsString as String, "application/plist")
+                        return nsString as String
                     }
                 } catch let serializationError as NSError {
-                    return ("Serialisation error: \(serializationError)", nil)
+                    return "Serialisation error: \(serializationError)"
                 }
             }
-            return ("Invalid object to serialise.", nil)
-        case .RAW(let body):
-            return (body, "application/octet-stream")
+            return "Invalid object to serialise."
+        case .STRING(let body):
+            return body
         case .HTML(let body):
-            return ("<html><body>\(body)</body></html>", "text/html")
+            return "<html><body>\(body)</body></html>"
         }
     }
 }
@@ -57,7 +57,7 @@ public enum HttpResponse {
     case MovedPermanently(String)
     case BadRequest, Unauthorized, Forbidden, NotFound
     case InternalServerError
-    case RAW(Int, NSData)
+    case RAW(Int, String, [String:String]?, NSData)
     
     func statusCode() -> Int {
         switch self {
@@ -70,7 +70,7 @@ public enum HttpResponse {
         case .Forbidden             : return 403
         case .NotFound              : return 404
         case .InternalServerError   : return 500
-        case .RAW(let code, _)      : return code
+        case .RAW(let code,_,_,_)   : return code
         }
     }
     
@@ -85,22 +85,34 @@ public enum HttpResponse {
         case .Forbidden             : return "Forbidden"
         case .NotFound              : return "Not Found"
         case .InternalServerError   : return "Internal Server Error"
-        case .RAW(_,_)              : return "Custom"
+        case .RAW(_,let pharse,_,_) : return pharse
         }
     }
     
     func headers() -> [String: String] {
         var headers = [String:String]()
-        headers["Server"] = "Swifter"
+        headers["Server"] = "Swifter \(HttpServer.VERSION)"
         switch self {
 		case .OK(let body):
-			let d = body.data()
-			if let ct = d.1
-			{
-				headers["Content-Type"] = ct
-			}
-			
-        case .MovedPermanently(let location) : headers["Location"] = location
+            switch body {
+                case .JSON(_)   : headers["Content-Type"] = "application/json"
+                case .PLIST(_)  : headers["Content-Type"] = "application/xml"
+                case .XML(_)    : headers["Content-Type"] = "application/xml"
+                // 'application/xml' vs 'text/xml'
+                // From RFC: http://www.rfc-editor.org/rfc/rfc3023.txt - "If an XML document -- that is, the unprocessed, source XML document -- is readable by casual users,
+                // text/xml is preferable to application/xml. MIME user agents (and web user agents) that do not have explicit 
+                // support for text/xml will treat it as text/plain, for example, by displaying the XML MIME entity as plain text. 
+                // Application/xml is preferable when the XML MIME entity is unreadable by casual users."
+                case .HTML(_)   : headers["Content-Type"] = "text/html"
+                default:[]
+            }
+        case .MovedPermanently(let location): headers["Location"] = location
+        case .RAW(_,_, let rawHeaders,_):
+            if let rawHeaders = rawHeaders {
+                for (k, v) in rawHeaders {
+                    headers.updateValue(v, forKey: k)
+                }
+            }
         default:[]
         }
         return headers
@@ -108,12 +120,9 @@ public enum HttpResponse {
     
     func body() -> NSData? {
         switch self {
-        case .OK(let body):
-			let d = body.data()
-			return d.0?.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
-			
-        case .RAW(_, let data)  : return data
-        default                 : return nil
+        case .OK(let body)          : return body.data()?.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
+        case .RAW(_,_,_, let data)  : return data
+        default                     : return nil
         }
     }
 }

+ 3 - 2
Common/HttpServer.swift

@@ -8,6 +8,8 @@ import Foundation
 
 public class HttpServer
 {
+    static let VERSION = "0.9";
+    
     public typealias Handler = HttpRequest -> HttpResponse
     
     var handlers: [(expression: NSRegularExpression, handler: Handler)] = []
@@ -18,8 +20,7 @@ public class HttpServer
     let matchingOptions = NSMatchingOptions(rawValue: 0)
     let expressionOptions = NSRegularExpressionOptions(rawValue: 0)
     
-    public init(){
-    }
+    public init() { }
     
     public subscript (path: String) -> Handler? {
         get {

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


+ 66 - 34
Swifter.xcodeproj/xcuserdata/damiankolakowski.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

@@ -202,11 +202,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "456827105.421335"
+            timestampString = "465835193.153472"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "44"
-            endingLineNumber = "44"
+            startingLineNumber = "45"
+            endingLineNumber = "45"
             landmarkName = "start(_:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -218,11 +218,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "456827105.421335"
+            timestampString = "465835193.153472"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "51"
-            endingLineNumber = "51"
+            startingLineNumber = "52"
+            endingLineNumber = "52"
             landmarkName = "start(_:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -234,11 +234,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "456827105.421335"
+            timestampString = "465835193.153472"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "53"
-            endingLineNumber = "53"
+            startingLineNumber = "54"
+            endingLineNumber = "54"
             landmarkName = "start(_:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -250,11 +250,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "456827105.421335"
+            timestampString = "465835193.153472"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "55"
-            endingLineNumber = "55"
+            startingLineNumber = "56"
+            endingLineNumber = "56"
             landmarkName = "start(_:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -266,11 +266,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "456827105.421335"
+            timestampString = "465835193.153472"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "59"
-            endingLineNumber = "59"
+            startingLineNumber = "60"
+            endingLineNumber = "60"
             landmarkName = "start(_:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -282,11 +282,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "456827105.421335"
+            timestampString = "465835193.153472"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "60"
-            endingLineNumber = "60"
+            startingLineNumber = "61"
+            endingLineNumber = "61"
             landmarkName = "start(_:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -314,12 +314,12 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "456827105.421335"
+            timestampString = "465835193.153472"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "83"
-            endingLineNumber = "83"
-            landmarkName = "captureExpressionGroups(_:value:)"
+            startingLineNumber = "84"
+            endingLineNumber = "84"
+            landmarkName = "findHandler(_:)"
             landmarkType = "5">
          </BreakpointContent>
       </BreakpointProxy>
@@ -346,11 +346,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "456827105.421335"
+            timestampString = "465835193.153472"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "56"
-            endingLineNumber = "56"
+            startingLineNumber = "57"
+            endingLineNumber = "57"
             landmarkName = "start(_:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -458,12 +458,12 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "456827105.421335"
+            timestampString = "465835193.153472"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "116"
-            endingLineNumber = "116"
-            landmarkName = "respond(_:response:keepAlive:)"
+            startingLineNumber = "117"
+            endingLineNumber = "117"
+            landmarkName = "stop()"
             landmarkType = "5">
          </BreakpointContent>
       </BreakpointProxy>
@@ -474,13 +474,13 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpServer.swift"
-            timestampString = "456827105.421335"
+            timestampString = "465835193.153472"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "117"
-            endingLineNumber = "117"
-            landmarkName = "respond(_:response:keepAlive:)"
-            landmarkType = "5">
+            startingLineNumber = "118"
+            endingLineNumber = "118"
+            landmarkName = "HttpServer"
+            landmarkType = "3">
          </BreakpointContent>
       </BreakpointProxy>
       <BreakpointProxy
@@ -878,5 +878,37 @@
             landmarkType = "5">
          </BreakpointContent>
       </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpResponse.swift"
+            timestampString = "465836128.222429"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "111"
+            endingLineNumber = "111"
+            landmarkName = "headers()"
+            landmarkType = "5">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpServer.swift"
+            timestampString = "465836185.461661"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "130"
+            endingLineNumber = "130"
+            landmarkName = "respond(_:response:keepAlive:)"
+            landmarkType = "5">
+         </BreakpointContent>
+      </BreakpointProxy>
    </Breakpoints>
 </Bucket>