HttpHandlers+Files.swift 6.1 KB

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