|
|
@@ -81,47 +81,76 @@ open class HttpRouter {
|
|
|
}
|
|
|
|
|
|
private func findHandler(_ node: inout Node, params: inout [String: String], generator: inout IndexingIterator<[String]>) -> ((HttpRequest) -> HttpResponse)? {
|
|
|
- guard let pathToken = generator.next()?.removingPercentEncoding else {
|
|
|
- // if it's the last element of the requested URL, check if there is a pattern with variable tail.
|
|
|
- if let variableNode = node.nodes.filter({ $0.0.first == ":" }).first {
|
|
|
- if variableNode.value.nodes.isEmpty {
|
|
|
- params[variableNode.0] = ""
|
|
|
- return variableNode.value.handler
|
|
|
+
|
|
|
+ var matchedRoutes = [Node]()
|
|
|
+ findHandler(&node, params: ¶ms, generator: &generator, matchedNodes: &matchedRoutes, index: 0, count: generator.reversed().count)
|
|
|
+ return matchedRoutes.first?.handler
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Find the handlers for a specified route
|
|
|
+ ///
|
|
|
+ /// - Parameters:
|
|
|
+ /// - node: The root node of the tree representing all the routes
|
|
|
+ /// - params: The parameters of the match
|
|
|
+ /// - generator: The IndexingIterator to iterate through the pattern to match
|
|
|
+ /// - matchedNodes: An array with the nodes matching the route
|
|
|
+ /// - index: The index of current position in the generator
|
|
|
+ /// - count: The number of elements if the route to match
|
|
|
+ private func findHandler(_ node: inout Node, params: inout [String: String], generator: inout IndexingIterator<[String]>, matchedNodes: inout [Node], index: Int, count: Int) {
|
|
|
+
|
|
|
+ if let pathToken = generator.next()?.removingPercentEncoding {
|
|
|
+
|
|
|
+ var currentIndex = index + 1
|
|
|
+ let variableNodes = node.nodes.filter { $0.0.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 search and
|
|
|
+ // append a tail as a value for the variable.
|
|
|
+ let tail = generator.joined(separator: "/")
|
|
|
+ if tail.count > 0 {
|
|
|
+ params[variableNode.0] = pathToken + "/" + tail
|
|
|
+ } else {
|
|
|
+ params[variableNode.0] = pathToken
|
|
|
+ }
|
|
|
+
|
|
|
+ matchedNodes.append(variableNode.value)
|
|
|
+ return
|
|
|
}
|
|
|
+ params[variableNode.0] = pathToken
|
|
|
+ findHandler(&node.nodes[variableNode.0]!, params: ¶ms, generator: &generator, matchedNodes: &matchedNodes, index: currentIndex, count: count)
|
|
|
}
|
|
|
- return node.handler
|
|
|
- }
|
|
|
- let variableNodes = node.nodes.filter { $0.0.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 search and
|
|
|
- // append a tail as a value for the variable.
|
|
|
- let tail = generator.joined(separator: "/")
|
|
|
- if tail.count > 0 {
|
|
|
- params[variableNode.0] = pathToken + "/" + tail
|
|
|
- } else {
|
|
|
- params[variableNode.0] = pathToken
|
|
|
- }
|
|
|
- return variableNode.1.handler
|
|
|
+
|
|
|
+ if var node = node.nodes[pathToken] {
|
|
|
+ findHandler(&node, params: ¶ms, generator: &generator, matchedNodes: &matchedNodes, index: currentIndex, count: count)
|
|
|
}
|
|
|
- params[variableNode.0] = pathToken
|
|
|
- return findHandler(&node.nodes[variableNode.0]!, params: ¶ms, generator: &generator)
|
|
|
- }
|
|
|
- if var node = node.nodes[pathToken] {
|
|
|
- return findHandler(&node, params: ¶ms, generator: &generator)
|
|
|
- }
|
|
|
- if var node = node.nodes["*"] {
|
|
|
- return findHandler(&node, params: ¶ms, generator: &generator)
|
|
|
- }
|
|
|
- if let startStarNode = node.nodes["**"] {
|
|
|
- let startStarNodeKeys = startStarNode.nodes.keys
|
|
|
- while let pathToken = generator.next() {
|
|
|
- if startStarNodeKeys.contains(pathToken) {
|
|
|
- return findHandler(&startStarNode.nodes[pathToken]!, params: ¶ms, generator: &generator)
|
|
|
+
|
|
|
+ if var node = node.nodes["*"] {
|
|
|
+ findHandler(&node, params: ¶ms, generator: &generator, matchedNodes: &matchedNodes, index: currentIndex, count: count)
|
|
|
+ }
|
|
|
+
|
|
|
+ if let startStarNode = node.nodes["**"] {
|
|
|
+ let startStarNodeKeys = startStarNode.nodes.keys
|
|
|
+ while let pathToken = generator.next() {
|
|
|
+ currentIndex += 1
|
|
|
+ if startStarNodeKeys.contains(pathToken) {
|
|
|
+ findHandler(&startStarNode.nodes[pathToken]!, params: ¶ms, generator: &generator, matchedNodes: &matchedNodes, index: currentIndex, count: count)
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+ } else if let variableNode = node.nodes.filter({ $0.0.first == ":" }).first {
|
|
|
+ // if it's the last element of the requested URL, check if there is a pattern with variable tail.
|
|
|
+ if variableNode.value.nodes.isEmpty {
|
|
|
+ params[variableNode.0] = ""
|
|
|
+ matchedNodes.append(variableNode.value)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // if it's the last element and the path to match is done then it's a pattern matching
|
|
|
+ if node.nodes.isEmpty && index == count {
|
|
|
+ matchedNodes.append(node)
|
|
|
+ return
|
|
|
}
|
|
|
- return nil
|
|
|
}
|
|
|
|
|
|
private func stripQuery(_ path: String) -> String {
|