WebDAV & SMB bug fix

upgraded to standard Foundation Library
This commit is contained in:
Amir Abbas Mousavian
2016-07-06 00:41:46 +04:30
parent d6059fc5df
commit 6443cc2a52
6 changed files with 1284 additions and 1186 deletions
+3 -3
View File
@@ -164,15 +164,15 @@ extension FileProvider {
}
internal func NotImplemented() {
assertionFailure("method not implemented")
assert(false, "method not implemented")
}
}
public protocol ExtendedFileProvider: FileProvider {
/*public protocol ExtendedFileProvider: FileProvider {
func thumbnailOfFileAtPath(path: String, dimension: CGSize, completionHandler: ((image: UIImage?, error: ErrorType?) -> Void))
func propertiesOfFileAtPath(path: String, completionHandler: ((propertiesDictionary: [String: AnyObject], keys: [String], error: ErrorType?) -> Void))
}
*/
public enum FileOperation {
case Create (path: String)
case Copy (source: String, destination: String)
+5 -5
View File
@@ -84,12 +84,12 @@ public class LocalFileProvider: FileProvider {
try self.fileManager.createDirectoryAtURL(self.absoluteURL(atPath).URLByAppendingPathComponent(folderName), withIntermediateDirectories: true, attributes: [:])
completionHandler?(error: nil)
dispatch_async(dispatch_get_main_queue(), {
self.delegate?.fileproviderSucceed(self, operation: .Create(path: atPath.stringByAppendingPathComponent(folderName) + "/"))
self.delegate?.fileproviderSucceed(self, operation: .Create(path: (atPath as NSString).stringByAppendingPathComponent(folderName) + "/"))
})
} catch let e as NSError {
completionHandler?(error: e)
dispatch_async(dispatch_get_main_queue(), {
self.delegate?.fileproviderFailed(self, operation: .Create(path: atPath.stringByAppendingPathComponent(folderName) + "/"))
self.delegate?.fileproviderFailed(self, operation: .Create(path: (atPath as NSString).stringByAppendingPathComponent(folderName) + "/"))
})
}
}
@@ -115,12 +115,12 @@ public class LocalFileProvider: FileProvider {
} catch _ {}
completionHandler?(error: nil)
dispatch_async(dispatch_get_main_queue(), {
self.delegate?.fileproviderSucceed(self, operation: .Create(path: atPath.stringByAppendingPathComponent(fileAttribs.name)))
self.delegate?.fileproviderSucceed(self, operation: .Create(path: (atPath as NSString).stringByAppendingPathComponent(fileAttribs.name)))
})
} else {
completionHandler?(error: self.throwError(atPath, code: NSURLError.CannotCreateFile))
dispatch_async(dispatch_get_main_queue(), {
self.delegate?.fileproviderFailed(self, operation: .Create(path: atPath.stringByAppendingPathComponent(fileAttribs.name)))
self.delegate?.fileproviderFailed(self, operation: .Create(path: (atPath as NSString).stringByAppendingPathComponent(fileAttribs.name)))
})
}
}
@@ -274,7 +274,7 @@ public class LocalFileProvider: FileProvider {
}
var result = [LocalFileObject]()
while let fileURL = iterator?.nextObject() as? NSURL {
if fileURL.fileName.lowercaseString.containsString(query.lowercaseString) {
if fileURL.lastPathComponent?.lowercaseString.containsString(query.lowercaseString) ?? false {
let fileObject = self.attributesOfItemAtURL(fileURL)
result.append(self.attributesOfItemAtURL(fileURL))
foundItemHandler?(fileObject)
File diff suppressed because it is too large Load Diff
+54 -1104
View File
File diff suppressed because it is too large Load Diff
-13
View File
@@ -8,19 +8,6 @@
import Foundation
internal func encode<T>(inout value: T) -> NSData {
return withUnsafePointer(&value) { p in
NSData(bytes: p, length: sizeofValue(value))
}
}
internal func decode<T>(data: NSData) -> T {
let pointer = UnsafeMutablePointer<T>.alloc(sizeof(T.Type))
data.getBytes(pointer, length: sizeof(T.Type))
return pointer.move()
}
class SMBFileProvider: FileProvider {
var type: String = "Samba"
var isPathRelative: Bool = true
+83 -61
View File
@@ -66,7 +66,11 @@ public class WebDAVFileProvider: NSObject, FileProvider {
public let isPathRelative: Bool = true
public let baseURL: NSURL?
public var currentPath: String = ""
public var dispatch_queue: dispatch_queue_t
public var dispatch_queue: dispatch_queue_t {
willSet {
assert(_session == nil, "It's not effective to change dispatch_queue property after session is initialized.")
}
}
public var delegate: FileProviderDelegate?
public let credential: NSURLCredential?
@@ -75,7 +79,9 @@ public class WebDAVFileProvider: NSObject, FileProvider {
private var _session: NSURLSession?
private var session: NSURLSession {
if _session == nil {
_session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: self, delegateQueue: nil)
let queue = NSOperationQueue()
queue.underlyingQueue = dispatch_queue
_session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: self, delegateQueue: queue)
}
return _session!
}
@@ -91,6 +97,7 @@ public class WebDAVFileProvider: NSObject, FileProvider {
}
deinit {
_session?.invalidateAndCancel()
}
public func contentsOfDirectoryAtPath(path: String, completionHandler: ((contents: [FileObjectClass], error: ErrorType?) -> Void)) {
@@ -107,19 +114,10 @@ public class WebDAVFileProvider: NSObject, FileProvider {
let xresponse = self.parseXMLResponse(data)
var fileObjects = [WebDavFileObject]()
for attr in xresponse {
let href = attr.href
if href.path == url.path {
if attr.href.path == url.path {
continue
}
let name = attr.prop["displayname"] ?? path.lastPathComponent
let size = Int64(attr.prop["getcontentlength"] ?? "-1") ?? NSURLSessionTransferSizeUnknown
let createdDate = self.resolveHTTPDate(attr.prop["creationdate"] ?? "")
let modifiedDate = self.resolveHTTPDate(attr.prop["getlastmodified"] ?? "")
let contentType = attr.prop["getcontenttype"] ?? "octet/stream"
let isDirectory = contentType == "httpd/unix-directory"
let entryTag = attr.prop["getetag"]
let fileObject = WebDavFileObject(absoluteURL: href, name: name, size: size, contentType: contentType, createdDate: createdDate, modifiedDate: modifiedDate, fileType: isDirectory ? .Directory : .Regular, isHidden: false, isReadOnly: false, entryTag: entryTag)
fileObjects.append(fileObject)
fileObjects.append(self.DavResponseToFileObject(attr))
}
completionHandler(contents: fileObjects, error: error)
return
@@ -141,16 +139,7 @@ public class WebDAVFileProvider: NSObject, FileProvider {
if let data = data {
let xresponse = self.parseXMLResponse(data)
if let attr = xresponse.first {
let href = attr.href
let name = attr.prop["displayname"] ?? path.lastPathComponent
let size = Int64(attr.prop["getcontentlength"] ?? "-1") ?? NSURLSessionTransferSizeUnknown
let createdDate = self.resolveHTTPDate(attr.prop["creationdate"] ?? "")
let modifiedDate = self.resolveHTTPDate(attr.prop["getlastmodified"] ?? "")
let contentType = attr.prop["getcontenttype"] ?? "octet/stream"
let isDirectory = contentType == "httpd/unix-directory"
let entryTag = attr.prop["getetag"]
let fileObject = WebDavFileObject(absoluteURL: href, name: name, size: size, contentType: contentType, createdDate: createdDate, modifiedDate: modifiedDate, fileType: isDirectory ? .Directory : .Regular, isHidden: false, isReadOnly: false, entryTag: entryTag)
completionHandler(attributes: fileObject, error: error)
completionHandler(attributes: self.DavResponseToFileObject(attr), error: error)
return
}
}
@@ -161,7 +150,7 @@ public class WebDAVFileProvider: NSObject, FileProvider {
public func createFolder(folderName: String, atPath: String, completionHandler: SimpleCompletionHandler) {
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
let url = absoluteURL(atPath.stringByAppendingPathComponent(folderName) + "/")
let url = absoluteURL((atPath as NSString).stringByAppendingPathComponent(folderName) + "/")
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "MKCOL"
request.setValue(baseURL?.absoluteString, forHTTPHeaderField: "Host")
@@ -173,9 +162,9 @@ public class WebDAVFileProvider: NSObject, FileProvider {
completionHandler?(error: error)
dispatch_async(dispatch_get_main_queue(), {
if error == nil {
self.delegate?.fileproviderSucceed(self, operation: .Create(path: atPath.stringByAppendingPathComponent(folderName) + "/"))
self.delegate?.fileproviderSucceed(self, operation: .Create(path: (atPath as NSString).stringByAppendingPathComponent(folderName) + "/"))
} else {
self.delegate?.fileproviderFailed(self, operation: .Create(path: atPath.stringByAppendingPathComponent(folderName) + "/"))
self.delegate?.fileproviderFailed(self, operation: .Create(path: (atPath as NSString).stringByAppendingPathComponent(folderName) + "/"))
}
})
}
@@ -189,13 +178,13 @@ public class WebDAVFileProvider: NSObject, FileProvider {
completionHandler?(error: error)
dispatch_async(dispatch_get_main_queue(), {
if error == nil {
self.delegate?.fileproviderSucceed(self, operation: .Create(path: path.stringByAppendingPathComponent(fileAttribs.name)))
self.delegate?.fileproviderSucceed(self, operation: .Create(path: (path as NSString).stringByAppendingPathComponent(fileAttribs.name)))
} else {
self.delegate?.fileproviderFailed(self, operation: .Create(path: path.stringByAppendingPathComponent(fileAttribs.name)))
self.delegate?.fileproviderFailed(self, operation: .Create(path: (path as NSString).stringByAppendingPathComponent(fileAttribs.name)))
}
})
}
task.taskDescription = self.dictionaryToJSON(["create": "create", "source": path.stringByAppendingPathComponent(fileAttribs.name)])
task.taskDescription = self.dictionaryToJSON(["type": "Create", "source": (path as NSString).stringByAppendingPathComponent(fileAttribs.name)])
task.resume()
}
@@ -379,7 +368,7 @@ public class WebDAVFileProvider: NSObject, FileProvider {
})
}
if atomically {
self.moveItemAtPath(path.stringByAppendingPathExtension("tmp")!, toPath: path, completionHandler: completionHandler)
self.moveItemAtPath((path as NSString).stringByAppendingPathExtension("tmp")!, toPath: path, completionHandler: completionHandler)
}
if let error = error {
// If there is no error, completionHandler has been executed by move command
@@ -405,18 +394,10 @@ public class WebDAVFileProvider: NSObject, FileProvider {
let xresponse = self.parseXMLResponse(data)
var fileObjects = [WebDavFileObject]()
for attr in xresponse {
let href = attr.href
let name = attr.prop["displayname"] ?? path.lastPathComponent
if !(href.path?.lastPathComponent.containsString(query) ?? false) {
if let path = attr.href.path where !((path as NSString).lastPathComponent.containsString(query)) {
continue
}
let size = Int64(attr.prop["getcontentlength"] ?? "-1") ?? NSURLSessionTransferSizeUnknown
let createdDate = self.resolveHTTPDate(attr.prop["creationdate"] ?? "")
let modifiedDate = self.resolveHTTPDate(attr.prop["getlastmodified"] ?? "")
let contentType = attr.prop["getcontenttype"] ?? "octet/stream"
let isDirectory = contentType == "httpd/unix-directory"
let entryTag = attr.prop["getetag"]
let fileObject = WebDavFileObject(absoluteURL: href, name: name, size: size, contentType: contentType, createdDate: createdDate, modifiedDate: modifiedDate, fileType: isDirectory ? .Directory : .Regular, isHidden: false, isReadOnly: false, entryTag: entryTag)
let fileObject = self.DavResponseToFileObject(attr)
fileObjects.append(fileObject)
foundItemHandler?(fileObject)
}
@@ -430,6 +411,12 @@ public class WebDAVFileProvider: NSObject, FileProvider {
public func registerNotifcation(path: String, eventHandler: (() -> Void)) {
NotImplemented()
/* There is no unified api for monitoring WebDAV server content change/update
* Microsoft Exchange uses SUBSCRIBE method, Apple uses push notification system.
* while both is unavailable in a mobile platform.
* A messy approach is listing a directory with an interval period and compare
* with previous results
*/
}
public func unregisterNotifcation(path: String) {
NotImplemented()
@@ -442,6 +429,7 @@ public class WebDAVFileProvider: NSObject, FileProvider {
internal extension WebDAVFileProvider {
struct DavResponse {
let href: NSURL
let hrefString: String
let status: Int?
let prop: [String: String]
}
@@ -450,25 +438,32 @@ internal extension WebDAVFileProvider {
var result = [DavResponse]()
do {
let xml = try AEXMLDocument(xmlData: response)
var rootnode = xml.root
var responsetag = "response"
for node in xml.root.all ?? [] {
if node.name.lowercaseString.hasSuffix("response") {
responsetag = node.name
for node in rootnode.all ?? [] {
if node.name.lowercaseString.hasSuffix("multistatus") {
rootnode = node
}
}
for responseNode in xml.root[responsetag].all ?? [] {
for node in rootnode.children ?? [] {
if node.name.lowercaseString.hasSuffix("response") {
responsetag = node.name
break
}
}
for responseNode in rootnode[responsetag].all ?? [] {
var hreftag = "href"
var statustag = "status"
var propstattag = "propstat"
for tnode in responseNode.all ?? [] {
if tnode.name.lowercaseString.hasSuffix("href") {
hreftag = tnode.name
for node in responseNode.children ?? [] {
if node.name.lowercaseString.hasSuffix("href") {
hreftag = node.name
}
if tnode.name.lowercaseString.hasSuffix("status") {
statustag = tnode.name
if node.name.lowercaseString.hasSuffix("status") {
statustag = node.name
}
if tnode.name.lowercaseString.hasSuffix("propstat") {
propstattag = tnode.name
if node.name.lowercaseString.hasSuffix("propstat") {
propstattag = node.name
}
}
let href = responseNode[hreftag].value
@@ -480,21 +475,32 @@ internal extension WebDAVFileProvider {
}
var propDic = [String: String]()
let propStatNode = responseNode[propstattag]
for node in propStatNode.children ?? [] {
if node.name.lowercaseString.hasSuffix("status") {
statustag = node.name
break
}
}
let statusDesc2 = (propStatNode[statustag].stringValue).componentsSeparatedByString(" ")
if statusDesc2.count > 2 {
status = Int(statusDesc2[1])
}
var proptag = "prop"
for tnode in propStatNode.all ?? [] {
for tnode in propStatNode.children ?? [] {
if tnode.name.lowercaseString.hasSuffix("prop") {
proptag = tnode.name
}
break
}
for propItemNode in propStatNode[proptag].all ?? [] {
for propItemNode in propStatNode[proptag].children ?? [] {
propDic[propItemNode.name.componentsSeparatedByString(":").last!.lowercaseString] = propItemNode.value
if propItemNode.name.hasSuffix("resourcetype") {
if propItemNode.xmlStringCompact.containsString("collection") {
propDic["getcontenttype"] = "httpd/unix-directory"
}
}
}
result.append(DavResponse(href: hrefURL, status: status, prop: propDic))
result.append(DavResponse(href: hrefURL, hrefString: href, status: status, prop: propDic))
}
}
} catch _ {
@@ -503,16 +509,32 @@ internal extension WebDAVFileProvider {
return result
}
func DavResponseToFileObject(davResponse: DavResponse) -> WebDavFileObject {
let href = davResponse.href
let name = davResponse.prop["displayname"] ?? (davResponse.hrefString.stringByRemovingPercentEncoding! as NSString).lastPathComponent
let size = Int64(davResponse.prop["getcontentlength"] ?? "-1") ?? NSURLSessionTransferSizeUnknown
let createdDate = self.resolveHTTPDate(davResponse.prop["creationdate"] ?? "")
let modifiedDate = self.resolveHTTPDate(davResponse.prop["getlastmodified"] ?? "")
let contentType = davResponse.prop["getcontenttype"] ?? "octet/stream"
let isDirectory = contentType == "httpd/unix-directory"
let entryTag = davResponse.prop["getetag"]
return WebDavFileObject(absoluteURL: href, name: name, size: size, contentType: contentType, createdDate: createdDate, modifiedDate: modifiedDate, fileType: isDirectory ? .Directory : .Regular, isHidden: false, isReadOnly: false, entryTag: entryTag)
}
func resolveHTTPDate(httpDateString: String) -> NSDate? {
if let rfc1123 = NSDate(string: httpDateString, withFormat: "EEE',' dd' 'MMM' 'yyyy HH':'mm':'ss zzz") {
return NSDate(timeIntervalSince1970: rfc1123.timeIntervalSince1970)
let dateFor: NSDateFormatter = NSDateFormatter()
dateFor.locale = NSLocale(localeIdentifier: "en_US")
dateFor.dateFormat = "EEE',' dd' 'MMM' 'yyyy HH':'mm':'ss zzz"
if let rfc1123 = dateFor.dateFromString(httpDateString) {
return rfc1123
}
if let rfc850 = NSDate(string: httpDateString, withFormat: "EEEE',' dd'-'MMM'-'yy HH':'mm':'ss z") {
return NSDate(timeIntervalSince1970: rfc850.timeIntervalSince1970)
dateFor.dateFormat = "EEEE',' dd'-'MMM'-'yy HH':'mm':'ss z"
if let rfc850 = dateFor.dateFromString(httpDateString) {
return rfc850
}
if let asctime = NSDate(string: httpDateString, withFormat: "EEE MMM d HH':'mm':'ss yyyy") {
return NSDate(timeIntervalSince1970: asctime.timeIntervalSince1970)
dateFor.dateFormat = "EEE MMM d HH':'mm':'ss yyyy"
if let asctime = dateFor.dateFromString(httpDateString) {
return asctime
}
//self.init()
return nil