| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- //
- // HttpRouter.swift
- // Swifter
- //
- // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved.
- //
- import Foundation
- public class HttpRouter {
-
- private class Node {
- var nodes = [String: Node]()
- var handler: (HttpRequest -> HttpResponse)? = nil
- }
-
- private var rootNode = Node()
- public func routes() -> [String] {
- var routes = [String]()
- for (_, child) in rootNode.nodes {
- routes.appendContentsOf(routesForNode(child));
- }
- return routes
- }
-
- private func routesForNode(node: Node, prefix: String = "") -> [String] {
- var result = [String]()
- if let _ = node.handler {
- result.append(prefix)
- }
- for (key, child) in node.nodes {
- result.appendContentsOf(routesForNode(child, prefix: prefix + "/" + key));
- }
- return result
- }
-
- public func register(method: String?, path: String, handler: (HttpRequest -> HttpResponse)?) {
- var pathSegments = stripQuery(path).split("/")
- if let method = method {
- pathSegments.insert(method, atIndex: 0)
- } else {
- pathSegments.insert("*", atIndex: 0)
- }
- var pathSegmentsGenerator = pathSegments.generate()
- inflate(&rootNode, generator: &pathSegmentsGenerator).handler = handler
- }
-
- public func route(method: String?, path: String) -> ([String: String], HttpRequest -> HttpResponse)? {
- if let method = method {
- let pathSegments = (method + "/" + stripQuery(path)).split("/")
- var pathSegmentsGenerator = pathSegments.generate()
- var params = [String:String]()
- if let handler = findHandler(&rootNode, params: ¶ms, generator: &pathSegmentsGenerator) {
- return (params, handler)
- }
- }
- let pathSegments = ("*/" + stripQuery(path)).split("/")
- var pathSegmentsGenerator = pathSegments.generate()
- var params = [String:String]()
- if let handler = findHandler(&rootNode, params: ¶ms, generator: &pathSegmentsGenerator) {
- return (params, handler)
- }
- return nil
- }
-
- private func inflate(inout node: Node, inout generator: IndexingGenerator<[String]>) -> Node {
- if let pathSegment = generator.next() {
- if let _ = node.nodes[pathSegment] {
- return inflate(&node.nodes[pathSegment]!, generator: &generator)
- }
- var nextNode = Node()
- node.nodes[pathSegment] = nextNode
- return inflate(&nextNode, generator: &generator)
- }
- return node
- }
-
- private func findHandler(inout node: Node, inout params: [String: String], inout generator: IndexingGenerator<[String]>) -> (HttpRequest -> HttpResponse)? {
- guard let pathToken = generator.next() else {
- return node.handler
- }
- let variableNodes = node.nodes.filter { $0.0.characters.first == ":" }
- if let variableNode = variableNodes.first {
- if variableNode.1.nodes.count == 0 {
- // if it's the last element of the pattern and it's a variable, stop the routing.
- params[variableNode.0] = pathToken + "/" + generator.joinWithSeparator("/")
- return variableNode.1.handler
- }
- params[variableNode.0] = pathToken
- return findHandler(&node.nodes[variableNode.0]!, params: ¶ms, generator: &generator)
- }
- if let _ = node.nodes[pathToken] {
- return findHandler(&node.nodes[pathToken]!, params: ¶ms, generator: &generator)
- }
- if let _ = node.nodes["*"] {
- return findHandler(&node.nodes["*"]!, params: ¶ms, generator: &generator)
- }
- return nil
- }
-
- private func stripQuery(path: String) -> String {
- if let path = path.split("?").first {
- return path
- }
- return path
- }
- }
|