Explorar o código

Merge pull request #1 from TENDIGI/content-ranges

Added support for HTTP `range` header
Nick Lee %!s(int64=10) %!d(string=hai) anos
pai
achega
d3e61036c6
Modificáronse 1 ficheiros con 51 adicións e 20 borrados
  1. 51 20
      Common/HttpHandlers.swift

+ 51 - 20
Common/HttpHandlers.swift

@@ -1,49 +1,80 @@
 //
 //  Handlers.swift
 //  Swifter
-//  Copyright (c) 2015 Damian Kołakowski. All rights reserved.
+//  Copyright (c) 2014 Damian Kołakowski. All rights reserved.
 //
 
 import Foundation
 
 public class HttpHandlers {
     
-    public class func file(path: String) -> ( HttpRequest -> HttpResponse ) {
-        return { request in
-            let filesPath = path.stringByExpandingTildeInPath
-            if let fileBody = NSData(contentsOfFile: filesPath) {
-                return HttpResponse.RAW(200, "OK", nil, fileBody)
-            }
-            return HttpResponse.NotFound
-        }
-    }
-
+    private static let rangeExpression = try! NSRegularExpression(pattern: "bytes=(\\d*)-(\\d*)", options: .CaseInsensitive)
+    
     public class func directory(dir: String) -> ( HttpRequest -> HttpResponse ) {
         return { request in
-            if let localPath = request.capturedUrlGroups.first {
-                let filesPath = dir.stringByExpandingTildeInPath.stringByAppendingPathComponent(localPath)
-                if let fileBody = NSData(contentsOfFile: filesPath) {
+            
+            guard let localPath = request.capturedUrlGroups.first else {
+                return HttpResponse.NotFound
+            }
+            
+            let filesPath = dir.stringByExpandingTildeInPath.stringByAppendingPathComponent(localPath)
+            
+            guard let fileBody = NSData(contentsOfFile: filesPath) else {
+                return HttpResponse.NotFound
+            }
+            
+            if let rangeHeader = request.headers["range"] {
+                
+                guard let match = rangeExpression.matchesInString(rangeHeader, options: .Anchored, range: NSRange(location: 0, length: rangeHeader.characters.count)).first where match.numberOfRanges == 3 else {
+                    return HttpResponse.BadRequest
+                }
+                
+                let startStr = (rangeHeader as NSString).substringWithRange(match.rangeAtIndex(1))
+                let endStr = (rangeHeader as NSString).substringWithRange(match.rangeAtIndex(2))
+                
+                guard let start = Int(startStr), end = Int(endStr) else {
                     return HttpResponse.RAW(200, "OK", nil, fileBody)
                 }
+                
+                let length = end - start
+                let range = NSRange(location: start, length: length + 1)
+                
+                guard range.location + range.length <= fileBody.length else {
+                    return HttpResponse.RAW(416, "Requested range not satisfiable", nil, NSData())
+                }
+                
+                let subData = fileBody.subdataWithRange(range)
+                
+                let headers = [
+                    "Content-Range" : "bytes \(startStr)-\(endStr)/\(fileBody.length)"
+                ]
+                
+                print(rangeHeader, headers)
+                
+                return HttpResponse.RAW(206, "Partial Content", headers, subData)
+                
             }
-            return HttpResponse.NotFound
+            else {
+                return HttpResponse.RAW(200, "OK", nil, fileBody)
+            }
+            
         }
     }
-
+    
     public class func directoryBrowser(dir: String) -> ( HttpRequest -> HttpResponse ) {
         return { request in
             if let pathFromUrl = request.capturedUrlGroups.first {
                 let filePath = dir.stringByExpandingTildeInPath.stringByAppendingPathComponent(pathFromUrl)
                 let fileManager = NSFileManager.defaultManager()
                 var isDir: ObjCBool = false;
-                if fileManager.fileExistsAtPath(filePath, isDirectory: &isDir) {
-                    if isDir {
+                if ( fileManager.fileExistsAtPath(filePath, isDirectory: &isDir) ) {
+                    if ( isDir ) {
                         do {
                             let files = try fileManager.contentsOfDirectoryAtPath(filePath)
                             var response = "<h3>\(filePath)</h3></br><table>"
                             response += files.map({ "<tr><td><a href=\"\(request.url)/\($0)\">\($0)</a></td></tr>"}).joinWithSeparator("")
                             response += "</table>"
-                            return HttpResponse.OK(.Html(response))
+                            return HttpResponse.OK(.HTML(response))
                         } catch  {
                             return HttpResponse.NotFound
                         }
@@ -63,7 +94,7 @@ private extension String {
     var stringByExpandingTildeInPath: String {
         return (self as NSString).stringByExpandingTildeInPath
     }
-
+    
     func stringByAppendingPathComponent(str: String) -> String {
         return (self as NSString).stringByAppendingPathComponent(str)
     }