HttpHandlers.swift 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. //
  2. // Handlers.swift
  3. // Swifter
  4. // Copyright (c) 2014 Damian Kołakowski. All rights reserved.
  5. //
  6. import Foundation
  7. public class HttpHandlers {
  8. private static let rangeExpression = try! NSRegularExpression(pattern: "bytes=(\\d*)-(\\d*)", options: .CaseInsensitive)
  9. private static let cache = NSCache()
  10. public class func directory(dir: String) -> ( HttpRequest -> HttpResponse ) {
  11. return { request in
  12. guard let localPath = request.params.first else {
  13. return HttpResponse.NotFound
  14. }
  15. let filesPath = dir + "/" + localPath.1
  16. let cachedBody = cache.objectForKey(filesPath) as? NSData
  17. guard let fileBody = cachedBody ?? NSData(contentsOfFile: filesPath) else {
  18. return HttpResponse.NotFound
  19. }
  20. if cachedBody == nil {
  21. cache.setObject(fileBody, forKey: filesPath)
  22. }
  23. if let rangeHeader = request.headers["range"] {
  24. guard let match = rangeExpression.matchesInString(rangeHeader, options: .Anchored, range: NSRange(location: 0, length: rangeHeader.characters.count)).first where match.numberOfRanges == 3 else {
  25. return HttpResponse.BadRequest
  26. }
  27. let startStr = (rangeHeader as NSString).substringWithRange(match.rangeAtIndex(1))
  28. let endStr = (rangeHeader as NSString).substringWithRange(match.rangeAtIndex(2))
  29. guard let start = Int(startStr), end = Int(endStr) else {
  30. var array = [UInt8](count: fileBody.length, repeatedValue: 0)
  31. fileBody.getBytes(&array, length: fileBody.length)
  32. return HttpResponse.RAW(200, "OK", nil, array)
  33. }
  34. let length = end - start
  35. let range = NSRange(location: start, length: length + 1)
  36. guard range.location + range.length <= fileBody.length else {
  37. return HttpResponse.RAW(416, "Requested range not satisfiable", nil, nil)
  38. }
  39. let subData = fileBody.subdataWithRange(range)
  40. let headers = [
  41. "Content-Range" : "bytes \(startStr)-\(endStr)/\(fileBody.length)"
  42. ]
  43. var array = [UInt8](count: subData.length, repeatedValue: 0)
  44. subData.getBytes(&array, length: subData.length)
  45. return HttpResponse.RAW(206, "Partial Content", headers, array)
  46. }
  47. else {
  48. var array = [UInt8](count: fileBody.length, repeatedValue: 0)
  49. fileBody.getBytes(&array, length: fileBody.length)
  50. return HttpResponse.RAW(200, "OK", nil, array)
  51. }
  52. }
  53. }
  54. public class func directoryBrowser(dir: String) -> ( HttpRequest -> HttpResponse ) {
  55. return { r in
  56. if let (_, value) = r.params.first {
  57. let filePath = dir + "/" + value
  58. let fileManager = NSFileManager.defaultManager()
  59. var isDir: ObjCBool = false;
  60. if ( fileManager.fileExistsAtPath(filePath, isDirectory: &isDir) ) {
  61. if ( isDir ) {
  62. do {
  63. let files = try fileManager.contentsOfDirectoryAtPath(filePath)
  64. var response = "<h3>\(filePath)</h3></br><table>"
  65. response += files.map({ "<tr><td><a href=\"\(r.url)/\($0)\">\($0)</a></td></tr>"}).joinWithSeparator("")
  66. response += "</table>"
  67. return HttpResponse.OK(.Html(response))
  68. } catch {
  69. return HttpResponse.NotFound
  70. }
  71. } else {
  72. if let fileBody = NSData(contentsOfFile: filePath) {
  73. var array = [UInt8](count: fileBody.length, repeatedValue: 0)
  74. fileBody.getBytes(&array, length: fileBody.length)
  75. return HttpResponse.RAW(200, "OK", nil, array)
  76. }
  77. }
  78. }
  79. }
  80. return HttpResponse.NotFound
  81. }
  82. }
  83. }