HttpRouter.swift 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. //
  2. // HttpRouter.swift
  3. // Swifter
  4. // Copyright (c) 2015 Damian Kołakowski. All rights reserved.
  5. //
  6. import Foundation
  7. public class HttpRouter {
  8. private var handlers: [(String?, pattern: [String], HttpRequest -> HttpResponse)] = []
  9. public func routes() -> [(method: String?, path: String)] {
  10. return handlers.map { ($0.0, "/" + $0.pattern.joinWithSeparator("/")) }
  11. }
  12. public func register(method: String?, path: String, handler: HttpRequest -> HttpResponse) {
  13. handlers.append((method, stripQuery(path).split("/"), handler))
  14. handlers.sortInPlace { $0.0.pattern.count < $0.1.pattern.count }
  15. }
  16. public func unregister(method: String?, path: String) {
  17. let pathTokens = stripQuery(path).split("/")
  18. handlers = handlers.filter { (meth, pattern, _) -> Bool in
  19. return meth != method || pattern != pathTokens
  20. }
  21. }
  22. public func select(method: String?, url: String) -> ([String: String], HttpRequest -> HttpResponse)? {
  23. let urlTokens = stripQuery(url).split("/")
  24. for (meth, pattern, handler) in handlers {
  25. if meth == nil || meth! == method {
  26. if let params = matchParams(pattern, valueTokens: urlTokens) {
  27. return (params, handler)
  28. }
  29. }
  30. }
  31. return nil
  32. }
  33. public func matchParams(patternTokens: [String], valueTokens: [String]) -> [String: String]? {
  34. var params = [String: String]()
  35. for index in 0..<valueTokens.count {
  36. if index >= patternTokens.count {
  37. return nil
  38. }
  39. let patternToken = patternTokens[index]
  40. let valueToken = valueTokens[index]
  41. if patternToken.isEmpty {
  42. if patternToken != valueToken {
  43. return nil
  44. }
  45. }
  46. if patternToken.characters.first == ":" {
  47. #if os(Linux)
  48. params[patternToken.substringFromIndex(1)] = valueToken
  49. #else
  50. params[patternToken.substringFromIndex(patternToken.characters.startIndex.successor())] = valueToken
  51. #endif
  52. } else {
  53. if patternToken != valueToken {
  54. return nil
  55. }
  56. }
  57. }
  58. return params
  59. }
  60. private func stripQuery(path: String) -> String {
  61. if let path = path.split("?").first {
  62. return path
  63. }
  64. return path
  65. }
  66. }