HttpHandlers+Files.swift 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. //
  2. // HttpHandlers+Files.swift
  3. // Swifter
  4. //
  5. // Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved.
  6. //
  7. import Foundation
  8. extension HttpHandlers {
  9. public class func shareFilesFromDirectory(directoryPath: String, chunkSize: Int = 64) -> (HttpRequest -> HttpResponse) {
  10. return { r in
  11. guard let absolutePath = self.fileNameToShare(directoryPath, request: r) else {
  12. return .NotFound
  13. }
  14. guard let file = try? File.openForReading(absolutePath) else {
  15. return .NotFound
  16. }
  17. return .RAW(200, "OK", [:], { writer in
  18. var buffer = [UInt8](count: chunkSize, repeatedValue: 0)
  19. while let count = try? file.read(&buffer) where count > 0 {
  20. writer.write(buffer[0 ..< count])
  21. }
  22. file.close()
  23. })
  24. }
  25. }
  26. private class func fileNameToShare(directoryPath: String, request: HttpRequest) -> String? {
  27. let path = request.path
  28. let fileRelativePath = request.params.first
  29. if !path.hasSuffix("/"), let fileRelativePath = fileRelativePath {
  30. let absolutePath = directoryPath + "/" + fileRelativePath.1
  31. return absolutePath
  32. }
  33. let fm = NSFileManager.defaultManager()
  34. let possibleIndexFiles = ["index.html", "index.htm"] // add any other files you want to check for here
  35. var folderPath = directoryPath
  36. if let fileRelativePath = fileRelativePath {
  37. folderPath += "/\(fileRelativePath.1)"
  38. }
  39. for indexFile in possibleIndexFiles {
  40. let indexPath = "\(folderPath)/\(indexFile)"
  41. if fm.fileExistsAtPath(indexPath) {
  42. return indexPath
  43. }
  44. }
  45. return nil
  46. }
  47. private static let rangePrefix = "bytes="
  48. public class func directory(dir: String) -> (HttpRequest -> HttpResponse) {
  49. return { r in
  50. guard let localPath = r.params.first else {
  51. return HttpResponse.NotFound
  52. }
  53. let filesPath = dir + "/" + localPath.1
  54. guard let fileBody = NSData(contentsOfFile: filesPath) else {
  55. return HttpResponse.NotFound
  56. }
  57. if let rangeHeader = r.headers["range"] {
  58. guard rangeHeader.hasPrefix(HttpHandlers.rangePrefix) else {
  59. return .BadRequest(.Text("Invalid value of 'Range' header: \(r.headers["range"])"))
  60. }
  61. #if os(Linux)
  62. let rangeString = rangeHeader.substringFromIndex(HttpHandlers.rangePrefix.characters.count)
  63. #else
  64. let rangeString = rangeHeader.substringFromIndex(rangeHeader.startIndex.advancedBy(HttpHandlers.rangePrefix.characters.count))
  65. #endif
  66. let rangeStringExploded = rangeString.split("-")
  67. guard rangeStringExploded.count == 2 else {
  68. return .BadRequest(.Text("Invalid value of 'Range' header: \(r.headers["range"])"))
  69. }
  70. let startStr = rangeStringExploded[0]
  71. let endStr = rangeStringExploded[1]
  72. guard let start = Int(startStr), end = Int(endStr) else {
  73. var array = [UInt8](count: fileBody.length, repeatedValue: 0)
  74. fileBody.getBytes(&array, length: fileBody.length)
  75. return HttpResponse.RAW(200, "OK", nil, { $0.write(array) })
  76. }
  77. let chunkLength = end - start
  78. let chunkRange = NSRange(location: start, length: chunkLength + 1)
  79. guard chunkRange.location + chunkRange.length <= fileBody.length else {
  80. return HttpResponse.RAW(416, "Requested range not satisfiable", nil, nil)
  81. }
  82. let chunk = fileBody.subdataWithRange(chunkRange)
  83. let headers = [ "Content-Range" : "bytes \(startStr)-\(endStr)/\(fileBody.length)" ]
  84. var content = [UInt8](count: chunk.length, repeatedValue: 0)
  85. chunk.getBytes(&content, length: chunk.length)
  86. return HttpResponse.RAW(206, "Partial Content", headers, { $0.write(content) })
  87. } else {
  88. var content = [UInt8](count: fileBody.length, repeatedValue: 0)
  89. fileBody.getBytes(&content, length: fileBody.length)
  90. return HttpResponse.RAW(200, "OK", nil, { $0.write(content) })
  91. }
  92. }
  93. }
  94. public class func directoryBrowser(dir: String) -> (HttpRequest -> HttpResponse) {
  95. return { r in
  96. guard let (_, value) = r.params.first else {
  97. return HttpResponse.NotFound
  98. }
  99. let filePath = dir + "/" + value
  100. let fileManager = NSFileManager.defaultManager()
  101. var isDir: ObjCBool = false
  102. guard fileManager.fileExistsAtPath(filePath, isDirectory: &isDir) else {
  103. return HttpResponse.NotFound
  104. }
  105. if isDir {
  106. do {
  107. let files = try fileManager.contentsOfDirectoryAtPath(filePath)
  108. var response = "<h3>\(filePath)</h3></br><table>"
  109. response += files.map({ "<tr><td><a href=\"\(r.path)/\($0)\">\($0)</a></td></tr>"}).joinWithSeparator("")
  110. response += "</table>"
  111. return HttpResponse.OK(.Html(response))
  112. } catch {
  113. return HttpResponse.NotFound
  114. }
  115. } else {
  116. if let content = NSData(contentsOfFile: filePath) {
  117. var array = [UInt8](count: content.length, repeatedValue: 0)
  118. content.getBytes(&array, length: content.length)
  119. return HttpResponse.RAW(200, "OK", nil, { $0.write(array) })
  120. }
  121. return HttpResponse.NotFound
  122. }
  123. }
  124. }
  125. }