Browse Source

Added parser for 'application/x-www-form-urlencoded' content type.

Damian Kołakowski 10 years ago
parent
commit
f8aec28a88

+ 3 - 9
Common/DemoServer.swift

@@ -58,13 +58,9 @@ func demoServer(publicDir: String?) -> HttpServer {
                         return .NotFound
                     }
                 }
-                break;
             case "POST":
-                if let body = request.body {
-                    return .OK(.HTML(body))
-                } else {
-                    return .OK(.HTML("No POST params."))
-            }
+                let formFields = request.parseForm()
+                return HttpResponse.OK(.HTML(formFields.map({ "\($0.0) = \($0.1)" }).joinWithSeparator("<br>")))
             default:
                 return .NotFound
         }
@@ -75,9 +71,7 @@ func demoServer(publicDir: String?) -> HttpServer {
     }
     server["/"] = { request in
         var listPage = "Available services:<br><ul>"
-        for item in server.routes() {
-            listPage += "<li><a href=\"\(item)\">\(item)</a></li>"
-        }
+        listPage += server.routes().map({ "<li><a href=\"\($0)\">\($0)</a></li>"}).joinWithSeparator("")
         listPage += "</ul>"
         return .OK(.HTML(listPage))
     }

+ 1 - 5
Common/HttpParser.swift

@@ -23,11 +23,7 @@ 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) {
-                // TODO detect content-type and handle:
-                // 'application/x-www-form-urlencoded' -> Dictionary
-                // 'multipart' -> Dictionary
                 if let contentLength = headers["content-length"], let contentLengthValue = Int(contentLength) {
                     let body = nextBody(socket, size: contentLengthValue, error: error)
                     return HttpRequest(url: path, urlParams: urlParams, method: method, headers: headers, body: body, capturedUrlGroups: [], address: nil)
@@ -45,7 +41,7 @@ class HttpParser {
                 if tokens.count >= 2 {
                     let key = tokens[0].stringByRemovingPercentEncoding
                     let value = tokens[1].stringByRemovingPercentEncoding
-                    if key != nil && value != nil { return (key!, value!) }
+                    if let key = key, value = value { return (key, value) }
                 }
                 return ("","")
             }

+ 16 - 0
Common/HttpRequest.swift

@@ -7,6 +7,7 @@
 import Foundation
 
 public struct HttpRequest {
+    
     public let url: String
     public let urlParams: [(String, String)] // http://stackoverflow.com/questions/1746507/authoritative-position-of-duplicate-http-get-query-keys
     public let method: String
@@ -14,4 +15,19 @@ public struct HttpRequest {
 	public let body: String?
     public var capturedUrlGroups: [String]
     public var address: String?
+    
+    public func parseForm() -> [(String, String)] {
+        if let body = body {
+            return body.componentsSeparatedByString("&").map { (param:String) -> (String, String) in
+                let tokens = param.componentsSeparatedByString("=")
+                if tokens.count >= 2 {
+                    let key = tokens[0].stringByReplacingOccurrencesOfString("+", withString: " ").stringByRemovingPercentEncoding
+                    let value = tokens[1].stringByReplacingOccurrencesOfString("+", withString: " ").stringByRemovingPercentEncoding
+                    if let key = key, value = value { return (key, value) }
+                }
+                return ("","")
+            }
+        }
+        return []
+    }
 }

+ 6 - 5
Common/HttpResponse.swift

@@ -46,7 +46,7 @@ public enum HttpResponseBody {
         case .STRING(let body):
             return body
         case .HTML(let body):
-            return "<html><body>\(body)</body></html>"
+            return "<html><meta charset=\"UTF-8\"><body>\(body)</body></html>"
         }
     }
 }
@@ -98,10 +98,11 @@ public enum HttpResponse {
                 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' or '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:[]

+ 2 - 2
Common/HttpServer.swift

@@ -32,8 +32,8 @@ public class HttpServer
                 if let newHandler = newValue {
                     handlers.append(expression: regex, handler: newHandler)
                 }
-            } catch {
-                    
+            } catch  {
+                print("Could not register handler for: \(path), error: \(error)")
             }
         }
     }

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


+ 47 - 31
Swifter.xcodeproj/xcuserdata/damiankolakowski.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

@@ -378,11 +378,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/DemoServer.swift"
-            timestampString = "456083936.619071"
+            timestampString = "466766836.996785"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "68"
-            endingLineNumber = "68"
+            startingLineNumber = "64"
+            endingLineNumber = "64"
             landmarkName = "demoServer(_:)"
             landmarkType = "7">
          </BreakpointContent>
@@ -410,11 +410,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpParser.swift"
-            timestampString = "438134345.357079"
+            timestampString = "466766836.996785"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "37"
-            endingLineNumber = "37"
+            startingLineNumber = "33"
+            endingLineNumber = "33"
             landmarkName = "nextHttpRequest(_:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -426,11 +426,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpParser.swift"
-            timestampString = "438134345.357079"
+            timestampString = "466766836.996785"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "36"
-            endingLineNumber = "36"
+            startingLineNumber = "32"
+            endingLineNumber = "32"
             landmarkName = "nextHttpRequest(_:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -766,22 +766,6 @@
             landmarkType = "5">
          </BreakpointContent>
       </BreakpointProxy>
-      <BreakpointProxy
-         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
-         <BreakpointContent
-            shouldBeEnabled = "No"
-            ignoreCount = "0"
-            continueAfterRunningActions = "No"
-            filePath = "Common/DemoServer.swift"
-            timestampString = "456083936.619071"
-            startingColumnNumber = "9223372036854775807"
-            endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "64"
-            endingLineNumber = "64"
-            landmarkName = "demoServer(_:)"
-            landmarkType = "7">
-         </BreakpointContent>
-      </BreakpointProxy>
       <BreakpointProxy
          BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
          <BreakpointContent
@@ -805,11 +789,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpParser.swift"
-            timestampString = "448798167.471669"
+            timestampString = "466766836.996785"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "27"
-            endingLineNumber = "27"
+            startingLineNumber = "26"
+            endingLineNumber = "26"
             landmarkName = "nextHttpRequest(_:error:)"
             landmarkType = "5">
          </BreakpointContent>
@@ -885,11 +869,11 @@
             ignoreCount = "0"
             continueAfterRunningActions = "No"
             filePath = "Common/HttpResponse.swift"
-            timestampString = "465836128.222429"
+            timestampString = "466766836.996785"
             startingColumnNumber = "9223372036854775807"
             endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "111"
-            endingLineNumber = "111"
+            startingLineNumber = "112"
+            endingLineNumber = "112"
             landmarkName = "headers()"
             landmarkType = "5">
          </BreakpointContent>
@@ -910,5 +894,37 @@
             landmarkType = "5">
          </BreakpointContent>
       </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpRequest.swift"
+            timestampString = "466766967.614148"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "20"
+            endingLineNumber = "20"
+            landmarkName = "parseForm()"
+            landmarkType = "5">
+         </BreakpointContent>
+      </BreakpointProxy>
+      <BreakpointProxy
+         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+         <BreakpointContent
+            shouldBeEnabled = "No"
+            ignoreCount = "0"
+            continueAfterRunningActions = "No"
+            filePath = "Common/HttpRequest.swift"
+            timestampString = "466767025.146182"
+            startingColumnNumber = "9223372036854775807"
+            endingColumnNumber = "9223372036854775807"
+            startingLineNumber = "22"
+            endingLineNumber = "22"
+            landmarkName = "parseForm()"
+            landmarkType = "5">
+         </BreakpointContent>
+      </BreakpointProxy>
    </Breakpoints>
 </Bucket>