diff --git a/FileProvider.podspec b/FileProvider.podspec
index d44c59a..be7463c 100644
--- a/FileProvider.podspec
+++ b/FileProvider.podspec
@@ -16,7 +16,7 @@ Pod::Spec.new do |s|
#
s.name = "FileProvider"
- s.version = "0.15.0"
+ s.version = "0.15.1"
s.summary = "FileManager replacement for Local and Remote (WebDAV/FTP/Dropbox/OneDrive/SMB2) files on iOS and macOS."
# This description is used to generate tags and improve search results.
diff --git a/FileProvider.xcodeproj/project.pbxproj b/FileProvider.xcodeproj/project.pbxproj
index 4d1eab1..edd2694 100644
--- a/FileProvider.xcodeproj/project.pbxproj
+++ b/FileProvider.xcodeproj/project.pbxproj
@@ -621,7 +621,7 @@
799396601D48B7BF00086753 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- BUNDLE_VERSION_STRING = 0.15.0;
+ BUNDLE_VERSION_STRING = 0.15.1;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
@@ -651,7 +651,7 @@
799396611D48B7BF00086753 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- BUNDLE_VERSION_STRING = 0.15.0;
+ BUNDLE_VERSION_STRING = 0.15.1;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
diff --git a/Sources/DropboxHelper.swift b/Sources/DropboxHelper.swift
index f057925..3133392 100644
--- a/Sources/DropboxHelper.swift
+++ b/Sources/DropboxHelper.swift
@@ -121,42 +121,8 @@ internal extension DropboxFileProvider {
task.resume()
}
- func upload_simple(_ targetPath: String, data: Data, modifiedDate: Date = Date(), overwrite: Bool, operation: FileOperationType, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
- if data.count > 150 * 1024 * 1024 {
- let error = FileProviderDropboxError(code: .payloadTooLarge, path: targetPath, errorDescription: nil)
- completionHandler?(error)
- self.delegateNotify(.create(path: targetPath), error: error)
- return nil
- }
- var requestDictionary = [String: AnyObject]()
- let url: URL
- url = URL(string: "files/upload", relativeTo: contentURL)!
- requestDictionary["path"] = correctPath(targetPath) as NSString?
- requestDictionary["mode"] = (overwrite ? "overwrite" : "add") as NSString
- requestDictionary["client_modified"] = modifiedDate.rfc3339utc() as NSString
- var request = URLRequest(url: url)
- request.httpMethod = "POST"
- request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
- request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
- request.setValue(String(jsonDictionary: requestDictionary), forHTTPHeaderField: "Dropbox-API-Arg")
- request.httpBody = data
- let task = session.uploadTask(with: request, from: data)
- completionHandlersForTasks[task.taskIdentifier] = completionHandler
- dataCompletionHandlersForTasks[task.taskIdentifier] = { [weak self] data in
- var responseError: FileProviderDropboxError?
- if let code = (task.response as? HTTPURLResponse)?.statusCode , code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) {
- responseError = FileProviderDropboxError(code: rCode, path: targetPath, errorDescription: String(data: data, encoding: .utf8))
- }
- completionHandler?(responseError)
- self?.delegateNotify(.create(path: targetPath), error: responseError)
- }
- task.taskDescription = operation.json
- task.resume()
- return RemoteOperationHandle(operationType: operation, tasks: [task])
- }
-
- func upload_simple(_ targetPath: String, localFile: URL, modifiedDate: Date = Date(), overwrite: Bool, operation: FileOperationType, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
- let size = (try? localFile.resourceValues(forKeys: [.fileSizeKey]))?.fileSize ?? -1
+ func upload_simple(_ targetPath: String, data: Data? = nil, localFile: URL? = nil, modifiedDate: Date = Date(), overwrite: Bool, operation: FileOperationType, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
+ let size = data?.count ?? Int((try? localFile?.resourceValues(forKeys: [.fileSizeKey]))??.fileSize ?? -1)
if size > 150 * 1024 * 1024 {
let error = FileProviderDropboxError(code: .payloadTooLarge, path: targetPath, errorDescription: nil)
completionHandler?(error)
@@ -174,15 +140,23 @@ internal extension DropboxFileProvider {
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
request.setValue(String(jsonDictionary: requestDictionary), forHTTPHeaderField: "Dropbox-API-Arg")
- let task = session.uploadTask(with: request, fromFile: localFile)
- completionHandlersForTasks[task.taskIdentifier] = completionHandler
- dataCompletionHandlersForTasks[task.taskIdentifier] = { [weak self] data in
+ let task: URLSessionUploadTask
+ if let data = data {
+ task = session.uploadTask(with: request, from: data)
+ } else if let localFile = localFile {
+ task = session.uploadTask(with: request, fromFile: localFile)
+ } else {
+ return nil
+ }
+
+ completionHandlersForTasks[task.taskIdentifier] = { [weak self] error in
var responseError: FileProviderDropboxError?
if let code = (task.response as? HTTPURLResponse)?.statusCode , code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) {
- responseError = FileProviderDropboxError(code: rCode, path: targetPath, errorDescription: String(data: data, encoding: .utf8))
+ // We can't fetch server result from delegate!
+ responseError = FileProviderDropboxError(code: rCode, path: targetPath, errorDescription: nil)
}
- completionHandler?(responseError)
- self?.delegateNotify(.create(path: targetPath), error: responseError)
+ completionHandler?(responseError ?? error)
+ self?.delegateNotify(.create(path: targetPath), error: responseError ?? error)
}
task.taskDescription = operation.json
task.resume()
diff --git a/Sources/LocalHelper.swift b/Sources/LocalHelper.swift
index 3f03453..9017285 100644
--- a/Sources/LocalHelper.swift
+++ b/Sources/LocalHelper.swift
@@ -37,7 +37,7 @@ public final class LocalFileObject: FileObject {
/// Initiates a `LocalFileObject` with attributes of file in url.
public convenience init?(fileWithURL fileURL: URL) {
do {
- let values = try fileURL.resourceValues(forKeys: [.nameKey, .fileSizeKey, .fileAllocatedSizeKey, .creationDateKey, .contentModificationDateKey, .fileResourceTypeKey, .isHiddenKey, .isWritableKey, .typeIdentifierKey, .generationIdentifierKey, .documentIdentifierKey])
+ let values = try fileURL.resourceValues(forKeys: [.nameKey, .fileSizeKey, .totalFileSizeKey, .fileAllocatedSizeKey, .totalFileAllocatedSizeKey, .creationDateKey, .contentModificationDateKey, .fileResourceTypeKey, .isHiddenKey, .isWritableKey, .typeIdentifierKey, .generationIdentifierKey, .documentIdentifierKey])
let path = fileURL.relativePath.hasPrefix("/") ? fileURL.relativePath : "/" + fileURL.relativePath
self.init(url: fileURL, name: values.name ?? fileURL.lastPathComponent, path: path)
diff --git a/Sources/OneDriveHelper.swift b/Sources/OneDriveHelper.swift
index 118b89e..03ede8c 100644
--- a/Sources/OneDriveHelper.swift
+++ b/Sources/OneDriveHelper.swift
@@ -113,37 +113,8 @@ internal extension OneDriveFileProvider {
task.resume()
}
- func upload_simple(_ targetPath: String, data: Data, modifiedDate: Date = Date(), overwrite: Bool, operation: FileOperationType, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
- if data.count > 100 * 1024 * 1024 {
- let error = FileProviderOneDriveError(code: .payloadTooLarge, path: targetPath, errorDescription: nil)
- completionHandler?(error)
- self.delegateNotify(.create(path: targetPath), error: error)
- return nil
- }
- let queryStr = overwrite ? "" : "?@name.conflictBehavior=fail"
- let url = self.url(of: targetPath, modifier: "content\(queryStr)")
- var request = URLRequest(url: url)
- request.httpMethod = "PUT"
- request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
- request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
- request.httpBody = data
- let task = session.uploadTask(with: request, from: data)
- completionHandlersForTasks[task.taskIdentifier] = completionHandler
- dataCompletionHandlersForTasks[task.taskIdentifier] = { [weak self] data in
- var responseError: FileProviderOneDriveError?
- if let code = (task.response as? HTTPURLResponse)?.statusCode , code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) {
- responseError = FileProviderOneDriveError(code: rCode, path: targetPath, errorDescription: String(data: data, encoding: .utf8))
- }
- completionHandler?(responseError)
- self?.delegateNotify(.create(path: targetPath), error: responseError)
- }
- task.taskDescription = operation.json
- task.resume()
- return RemoteOperationHandle(operationType: operation, tasks: [task])
- }
-
- func upload_simple(_ targetPath: String, localFile: URL, modifiedDate: Date = Date(), overwrite: Bool, operation: FileOperationType, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
- let size = (try? localFile.resourceValues(forKeys: [.fileSizeKey]))?.fileSize ?? -1
+ func upload_simple(_ targetPath: String, data: Data? = nil , localFile: URL? = nil, modifiedDate: Date = Date(), overwrite: Bool, operation: FileOperationType, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
+ let size = data?.count ?? (try? localFile?.resourceValues(forKeys: [.fileSizeKey]))??.fileSize ?? -1
if size > 100 * 1024 * 1024 {
let error = FileProviderOneDriveError(code: .payloadTooLarge, path: targetPath, errorDescription: nil)
completionHandler?(error)
@@ -156,15 +127,23 @@ internal extension OneDriveFileProvider {
request.httpMethod = "PUT"
request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization")
request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
- let task = session.uploadTask(with: request, fromFile: localFile)
- completionHandlersForTasks[task.taskIdentifier] = completionHandler
- dataCompletionHandlersForTasks[task.taskIdentifier] = { [weak self] data in
+ let task: URLSessionUploadTask
+ if let data = data {
+ task = session.uploadTask(with: request, from: data)
+ } else if let localFile = localFile {
+ task = session.uploadTask(with: request, fromFile: localFile)
+ } else {
+ return nil
+ }
+
+ completionHandlersForTasks[task.taskIdentifier] = { [weak self] error in
var responseError: FileProviderOneDriveError?
if let code = (task.response as? HTTPURLResponse)?.statusCode , code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) {
- responseError = FileProviderOneDriveError(code: rCode, path: targetPath, errorDescription: String(data: data, encoding: .utf8))
+ // We can't fetch server result from delegate!
+ responseError = FileProviderOneDriveError(code: rCode, path: targetPath, errorDescription: nil)
}
- completionHandler?(responseError)
- self?.delegateNotify(.create(path: targetPath), error: responseError)
+ completionHandler?(responseError ?? error)
+ self?.delegateNotify(.create(path: targetPath), error: responseError ?? error)
}
task.taskDescription = operation.json
task.resume()
diff --git a/Sources/RemoteSession.swift b/Sources/RemoteSession.swift
index 08895b1..c46550a 100644
--- a/Sources/RemoteSession.swift
+++ b/Sources/RemoteSession.swift
@@ -111,11 +111,9 @@ class SessionDelegate: NSObject, URLSessionDataDelegate, URLSessionDownloadDeleg
// codebeat:disable[ARITY]
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
- if error != nil {
- let completionHandler = completionHandlersForTasks[task.taskIdentifier] ?? nil
- completionHandler?(error)
- completionHandlersForTasks.removeValue(forKey: task.taskIdentifier)
- }
+ let completionHandler = completionHandlersForTasks[task.taskIdentifier] ?? nil
+ completionHandler?(error)
+ completionHandlersForTasks.removeValue(forKey: task.taskIdentifier)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
diff --git a/Sources/WebDAVFileProvider.swift b/Sources/WebDAVFileProvider.swift
index 566cb6c..65922da 100644
--- a/Sources/WebDAVFileProvider.swift
+++ b/Sources/WebDAVFileProvider.swift
@@ -120,14 +120,29 @@ open class WebDAVFileProvider: FileProviderBasicRemote {
}
}
- open func contentsOfDirectory(path: String, completionHandler: @escaping ((_ contents: [FileObject], _ error: Error?) -> Void)) {
+ public func contentsOfDirectory(path: String, completionHandler: @escaping (([FileObject], Error?) -> Void)) {
+ self.contentsOfDirectory(path: path, including: [], completionHandler: completionHandler)
+ }
+
+ /**
+ Returns an Array of `FileObject`s identifying the the directory entries via asynchronous completion handler.
+
+ If the directory contains no entries or an error is occured, this method will return the empty array.
+
+ - Parameter path: path to target directory. If empty, `currentPath` value will be used.
+ - Parameter including: An array which determines which file properties should be considered to fetch.
+ - Parameter completionHandler: a closure with result of directory entries or error.
+ - `contents`: An array of `FileObject` identifying the the directory entries.
+ - `error`: Error returned by system.
+ */
+ open func contentsOfDirectory(path: String, including: [URLResourceKey], completionHandler: @escaping ((_ contents: [FileObject], _ error: Error?) -> Void)) {
let opType = FileOperationType.fetch(path: path)
let url = self.url(of: path).appendingPathComponent("")
var request = URLRequest(url: url)
request.httpMethod = "PROPFIND"
request.setValue("1", forHTTPHeaderField: "Depth")
request.setValue("text/xml; charset=\"utf-8\"", forHTTPHeaderField: "Content-Type")
- request.httpBody = "\n\n".data(using: .utf8)
+ request.httpBody = "\n\n\(WebDavFileObject.propString(including))\n".data(using: .utf8)
request.setValue(String(request.httpBody!.count), forHTTPHeaderField: "Content-Length")
runDataTask(with: request, operationHandle: RemoteOperationHandle(operationType: opType, tasks: []), completionHandler: { (data, response, error) in
var responseError: FileProviderWebDavError?
@@ -149,12 +164,27 @@ open class WebDAVFileProvider: FileProviderBasicRemote {
}
open func attributesOfItem(path: String, completionHandler: @escaping ((_ attributes: FileObject?, _ error: Error?) -> Void)) {
+ self.attributesOfItem(path: path, including: [], completionHandler: completionHandler)
+ }
+
+ /**
+ Returns a `FileObject` containing the attributes of the item (file, directory, symlink, etc.) at the path in question via asynchronous completion handler.
+
+ If the directory contains no entries or an error is occured, this method will return the empty `FileObject`.
+
+ - Parameter path: path to target directory. If empty, `currentPath` value will be used.
+ - Parameter including: An array which determines which file properties should be considered to fetch.
+ - Parameter completionHandler: a closure with result of directory entries or error.
+ - `attributes`: A `FileObject` containing the attributes of the item.
+ - `error`: Error returned by system.
+ */
+ open func attributesOfItem(path: String, including: [URLResourceKey], completionHandler: @escaping ((_ attributes: FileObject?, _ error: Error?) -> Void)) {
let url = self.url(of: path)
var request = URLRequest(url: url)
request.httpMethod = "PROPFIND"
request.setValue("1", forHTTPHeaderField: "Depth")
request.setValue("text/xml; charset=\"utf-8\"", forHTTPHeaderField: "Content-Type")
- request.httpBody = "\n\n".data(using: .utf8)
+ request.httpBody = "\n\n\(WebDavFileObject.propString(including))\n".data(using: .utf8)
request.setValue(String(request.httpBody!.count), forHTTPHeaderField: "Content-Length")
runDataTask(with: request, completionHandler: { (data, response, error) in
var responseError: FileProviderWebDavError?
@@ -356,14 +386,14 @@ extension WebDAVFileProvider: FileProviderOperations {
}
request.httpMethod = "PUT"
let task = session.uploadTask(with: request, fromFile: localFile)
- completionHandlersForTasks[task.taskIdentifier] = completionHandler
- dataCompletionHandlersForTasks[task.taskIdentifier] = { [weak self] data in
+ completionHandlersForTasks[task.taskIdentifier] = { [weak self] error in
var responseError: FileProviderWebDavError?
if let code = (task.response as? HTTPURLResponse)?.statusCode , code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) {
- responseError = FileProviderWebDavError(code: rCode, path: toPath, errorDescription: String(data: data, encoding: .utf8), url: url)
+ // We can't fetch server result from delegate!
+ responseError = FileProviderWebDavError(code: rCode, path: toPath, errorDescription: nil, url: url)
}
- completionHandler?(responseError)
- self?.delegateNotify(.create(path: toPath), error: responseError)
+ completionHandler?(responseError ?? error)
+ self?.delegateNotify(.create(path: toPath), error: responseError ?? error)
}
task.taskDescription = opType.json
task.resume()
@@ -444,14 +474,14 @@ extension WebDAVFileProvider: FileProviderReadWrite {
request.setValue("F", forHTTPHeaderField: "Overwrite")
}
let task = session.uploadTask(with: request, from: data ?? Data())
- completionHandlersForTasks[task.taskIdentifier] = completionHandler
- dataCompletionHandlersForTasks[task.taskIdentifier] = { [weak self] data in
+ completionHandlersForTasks[task.taskIdentifier] = { [weak self] error in
var responseError: FileProviderWebDavError?
if let code = (task.response as? HTTPURLResponse)?.statusCode , code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) {
- responseError = FileProviderWebDavError(code: rCode, path: path, errorDescription: String(data: data, encoding: .utf8), url: url)
+ // We can't fetch server result from delegate!
+ responseError = FileProviderWebDavError(code: rCode, path: path, errorDescription: nil, url: url)
}
- completionHandler?(responseError)
- self?.delegateNotify(.create(path: path), error: responseError)
+ completionHandler?(responseError ?? error)
+ self?.delegateNotify(.create(path: path), error: responseError ?? error)
}
task.taskDescription = opType.json
task.resume()
@@ -591,7 +621,7 @@ struct DavResponse {
public final class WebDavFileObject: FileObject {
internal init(_ davResponse: DavResponse) {
let href = davResponse.href
- let name = davResponse.prop["displayname"] ?? (davResponse.hrefString.removingPercentEncoding! as NSString).lastPathComponent
+ let name = davResponse.prop["displayname"] ?? davResponse.href.lastPathComponent
let relativePath = href.relativePath
let path = relativePath.hasPrefix("/") ? relativePath : ("/" + relativePath)
super.init(url: href, name: name, path: path)
@@ -623,6 +653,38 @@ public final class WebDavFileObject: FileObject {
allValues[.entryTag] = newValue
}
}
+
+ internal class func resourceKeyToDAVProp(_ key: URLResourceKey) -> String? {
+ switch key {
+ case URLResourceKey.fileSizeKey:
+ return "getcontentlength"
+ case URLResourceKey.creationDateKey:
+ return "creationdate"
+ case URLResourceKey.contentModificationDateKey:
+ return "getlastmodified"
+ case URLResourceKey.fileResourceTypeKey, URLResourceKey.mimeType:
+ return "getcontenttype"
+ case URLResourceKey.isHiddenKey:
+ return "ishidden"
+ case URLResourceKey.entryTag:
+ return "getetag"
+ default:
+ return nil
+ }
+ }
+
+ internal class func propString(_ keys: [URLResourceKey]) -> String {
+ var propKeys = ""
+ for item in keys {
+ if let prop = WebDavFileObject.resourceKeyToDAVProp(item) {
+ propKeys += ""
+ }
+ }
+ if propKeys.isEmpty {
+ propKeys = ""
+ }
+ return propKeys
+ }
}
/// Error returned by WebDAV server when trying to access or do operations on a file or folder.