1
0

HttpRouter.swift 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. //
  2. // HttpRouter.swift
  3. // Swifter
  4. //
  5. // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved.
  6. //
  7. import Foundation
  8. public class HttpRouter {
  9. private class Node {
  10. var nodes = [String: Node]()
  11. var handler: (HttpRequest -> HttpResponse)? = nil
  12. }
  13. private var rootNode = Node()
  14. public func routes() -> [String] {
  15. var routes = [String]()
  16. for (_, child) in rootNode.nodes {
  17. routes.appendContentsOf(routesForNode(child));
  18. }
  19. return routes
  20. }
  21. private func routesForNode(node: Node, prefix: String = "") -> [String] {
  22. var result = [String]()
  23. if let _ = node.handler {
  24. result.append(prefix)
  25. }
  26. for (key, child) in node.nodes {
  27. result.appendContentsOf(routesForNode(child, prefix: prefix + "/" + key));
  28. }
  29. return result
  30. }
  31. public func register(method: String?, path: String, handler: (HttpRequest -> HttpResponse)?) {
  32. var pathSegments = stripQuery(path).split("/")
  33. if let method = method {
  34. pathSegments.insert(method, atIndex: 0)
  35. } else {
  36. pathSegments.insert("*", atIndex: 0)
  37. }
  38. var pathSegmentsGenerator = pathSegments.generate()
  39. inflate(&rootNode, generator: &pathSegmentsGenerator).handler = handler
  40. }
  41. public func route(method: String?, path: String) -> ([String: String], HttpRequest -> HttpResponse)? {
  42. if let method = method {
  43. let pathSegments = (method + "/" + stripQuery(path)).split("/")
  44. var pathSegmentsGenerator = pathSegments.generate()
  45. var params = [String:String]()
  46. if let handler = findHandler(&rootNode, params: &params, generator: &pathSegmentsGenerator) {
  47. return (params, handler)
  48. }
  49. }
  50. let pathSegments = ("*/" + stripQuery(path)).split("/")
  51. var pathSegmentsGenerator = pathSegments.generate()
  52. var params = [String:String]()
  53. if let handler = findHandler(&rootNode, params: &params, generator: &pathSegmentsGenerator) {
  54. return (params, handler)
  55. }
  56. return nil
  57. }
  58. private func inflate(inout node: Node, inout generator: IndexingGenerator<[String]>) -> Node {
  59. if let pathSegment = generator.next() {
  60. if let _ = node.nodes[pathSegment] {
  61. return inflate(&node.nodes[pathSegment]!, generator: &generator)
  62. }
  63. var nextNode = Node()
  64. node.nodes[pathSegment] = nextNode
  65. return inflate(&nextNode, generator: &generator)
  66. }
  67. return node
  68. }
  69. private func findHandler(inout node: Node, inout params: [String: String], inout generator: IndexingGenerator<[String]>) -> (HttpRequest -> HttpResponse)? {
  70. guard let pathToken = generator.next() else {
  71. return node.handler
  72. }
  73. let variableNodes = node.nodes.filter { $0.0.characters.first == ":" }
  74. if let variableNode = variableNodes.first {
  75. if variableNode.1.nodes.count == 0 {
  76. // if it's the last element of the pattern and it's a variable, stop the routing.
  77. params[variableNode.0] = pathToken + "/" + generator.joinWithSeparator("/")
  78. return variableNode.1.handler
  79. }
  80. params[variableNode.0] = pathToken
  81. return findHandler(&node.nodes[variableNode.0]!, params: &params, generator: &generator)
  82. }
  83. if let _ = node.nodes[pathToken] {
  84. return findHandler(&node.nodes[pathToken]!, params: &params, generator: &generator)
  85. }
  86. if let _ = node.nodes["*"] {
  87. return findHandler(&node.nodes["*"]!, params: &params, generator: &generator)
  88. }
  89. return nil
  90. }
  91. private func stripQuery(path: String) -> String {
  92. if let path = path.split("?").first {
  93. return path
  94. }
  95. return path
  96. }
  97. }