FTP better error handling

This commit is contained in:
Amir Abbas Mousavian
2017-03-30 13:16:03 +04:30
parent bf62d585fd
commit 4dbb0adb18
3 changed files with 95 additions and 18 deletions
+3 -3
View File
@@ -551,7 +551,7 @@ internal protocol FPSStreamDelegate : URLSessionTaskDelegate {
@objc optional func urlSession(_ session: URLSession, streamTask: FPSStreamTask, didBecome inputStream: InputStream, outputStream: OutputStream)
}
private let ports: [String: Int] = ["http": 80, "https": 443, "smb": 445,"ftp": 21,"ftps": 22, "sftp": 2121,
private let ports: [String: Int] = ["http": 80, "https": 443, "smb": 445,"ftp": 21,
"telnet": 23, "pop": 110, "smtp": 25, "imap": 143]
private let securePorts: [String: Int] = ["https": 443, "smb": 445, "ftps": 990, "sftp": 2121,
"telnet": 992, "pop": 995, "smtp": 465, "imap": 993]
private let securePorts: [String: Int] = ["ssh": 22, "https": 443, "smb": 445, "smtp": 465,
"ftps": 990,"telnet": 992, "imap": 993, "pop": 995]
+5 -2
View File
@@ -199,7 +199,7 @@ open class FTPFileProvider: FileProviderBasicRemote {
return
}
guard let response = response, response.hasPrefix("250") else {
guard let response = response, response.hasPrefix("250") || (response.hasPrefix("50") && rfc3659enabled) else {
let error = NSError(domain: URLError.errorDomain, code: URLError.badServerResponse.rawValue, userInfo: nil)
self.dispatch_queue.async {
completionHandler(nil, error)
@@ -207,6 +207,10 @@ open class FTPFileProvider: FileProviderBasicRemote {
return
}
if response.hasPrefix("500") {
self.attributesOfItem(path: path, rfc3659enabled: false, completionHandler: completionHandler)
}
let lines = response.components(separatedBy: "\n").flatMap { $0.isEmpty ? nil : $0.trimmingCharacters(in: .whitespacesAndNewlines) }
guard lines.count > 2 else {
let error = NSError(domain: URLError.errorDomain, code: URLError.badServerResponse.rawValue, userInfo: nil)
@@ -224,7 +228,6 @@ open class FTPFileProvider: FileProviderBasicRemote {
}
open func storageProperties(completionHandler: @escaping ((_ total: Int64, _ used: Int64) -> Void)) {
// TODO: implement SITE QUOTA extension
dispatch_queue.async {
completionHandler(-1, 0)
}
+87 -13
View File
@@ -88,7 +88,10 @@ extension FTPFileProvider {
}
guard response.hasPrefix("22") else {
let error = NSError(domain: URLError.errorDomain, code: URLError.cannotConnectToHost.rawValue, userInfo: nil)
let spaceIndex = response.characters.index(of: " ") ?? response.startIndex
let code = Int(response.substring(to: spaceIndex).trimmingCharacters(in: .whitespacesAndNewlines)) ?? -1
let description = response.substring(from: spaceIndex).trimmingCharacters(in: .whitespacesAndNewlines)
let error = FileProviderFTPError(code: code, path: "", errorDescription: description)
completionHandler(error)
return
}
@@ -108,8 +111,8 @@ extension FTPFileProvider {
// successfully logged in
if response.hasPrefix("23") {
completionHandler(nil)
return
}
// needs password
@@ -122,17 +125,20 @@ extension FTPFileProvider {
completionHandler(error)
}
}
return
}
let spaceIndex = response.characters.index(of: " ") ?? response.startIndex
let code = Int(response.substring(to: spaceIndex).trimmingCharacters(in: .whitespacesAndNewlines)) ?? -1
let description = response.substring(from: spaceIndex).trimmingCharacters(in: .whitespacesAndNewlines)
let error = FileProviderFTPError(code: code, path: "", errorDescription: description)
completionHandler(error)
return
}
}
if self.baseURL?.scheme == "ftps" {
self.execute(command: "AUTH TLS", on: task, completionHandler: { (response, error) in
if let error = error {
completionHandler(error)
return
}
self.execute(command: "AUTH TLS", on: task, minLength: 0, completionHandler: { (response, error) in
task.startSecureConnection()
loginHandle()
})
@@ -161,8 +167,12 @@ extension FTPFileProvider {
}
// not logged in
else if response.hasPrefix("55") {
let error = NSError(domain: URLError.errorDomain, code: URLError.fileDoesNotExist.rawValue, userInfo: nil)
let spaceIndex = response.characters.index(of: " ") ?? response.startIndex
let code = Int(response.substring(to: spaceIndex).trimmingCharacters(in: .whitespacesAndNewlines)) ?? -1
let description = response.substring(from: spaceIndex).trimmingCharacters(in: .whitespacesAndNewlines)
let error = FileProviderFTPError(code: code, path: "", errorDescription: description)
completionHandler(error)
return
}
}
}
@@ -214,8 +224,12 @@ extension FTPFileProvider {
if response?.hasPrefix("35") ?? false {
completionHandler(nil)
} else {
let error = NSError(domain: URLError.errorDomain, code: URLError.resourceUnavailable.rawValue, userInfo: nil)
let spaceIndex = response?.characters.index(of: " ") ?? response?.startIndex
let code = Int((response?.substring(to: spaceIndex!).trimmingCharacters(in: .whitespacesAndNewlines))!) ?? -1
let description = response?.substring(from: spaceIndex!).trimmingCharacters(in: .whitespacesAndNewlines)
let error = FileProviderFTPError(code: code, path: "", errorDescription: description)
completionHandler(error)
return
}
}
}
@@ -288,12 +302,34 @@ extension FTPFileProvider {
completionHandler([], error)
return
}
guard let response = response else {
let badResponseError = NSError(domain: URLError.errorDomain, code: URLError.cannotParseResponse.rawValue, userInfo: nil)
completionHandler([], badResponseError)
return
}
if response.hasPrefix("50") && useMLST {
self.ftpList(task, of: path, useMLST: false, completionHandler: completionHandler)
return
}
if !response.hasPrefix("25") {
let spaceIndex = response.characters.index(of: " ") ?? response.startIndex
let code = Int(response.substring(to: spaceIndex).trimmingCharacters(in: .whitespacesAndNewlines)) ?? -1
let description = response.substring(from: spaceIndex).trimmingCharacters(in: .whitespacesAndNewlines)
let error = FileProviderFTPError(code: code, path: "", errorDescription: description)
self.dispatch_queue.async {
completionHandler([], error)
}
return
}
}
}
}
func ftpRetrieve(_ task: FPSStreamTask, filePath: String, from position: Int64 = 0, length: Int = -1, onTask: ((_ task: FPSStreamTask) -> Void)?, completionHandler: @escaping (_ data: Data?, _ error: Error?) -> Void) {
// FIXME: retreiven't begain
self.ftpPassive(task) { (host, port, error) in
if let error = error {
completionHandler(nil, error)
@@ -307,7 +343,6 @@ extension FTPFileProvider {
}
// Send retreive command
// FIXME: use crlf instead of length
self.execute(command: "REST \(position)\r\nRETR \(filePath)", on: task, minLength: 75, afterSend: { error in
// starting passive task
let timeout = self.session.configuration.timeoutIntervalForRequest
@@ -358,6 +393,23 @@ extension FTPFileProvider {
return
}
guard let response = response else {
let badResponseError = NSError(domain: URLError.errorDomain, code: URLError.cannotParseResponse.rawValue, userInfo: nil)
completionHandler(nil, badResponseError)
return
}
if !(response.hasPrefix("1") || !response.hasPrefix("2")) {
let spaceIndex = response.characters.index(of: " ") ?? response.startIndex
let code = Int(response.substring(to: spaceIndex).trimmingCharacters(in: .whitespacesAndNewlines)) ?? -1
let description = response.substring(from: spaceIndex).trimmingCharacters(in: .whitespacesAndNewlines)
let error = FileProviderFTPError(code: code, path: "", errorDescription: description)
self.dispatch_queue.async {
completionHandler(nil, error)
}
return
}
}
}
}
@@ -377,7 +429,6 @@ extension FTPFileProvider {
}
// Send retreive command
// FIXME: use crlf instead of length
self.execute(command: "STOR \(filePath)", on: task, minLength: 75, afterSend: { error in
// starting passive task
let timeout = self.session.configuration.timeoutIntervalForRequest
@@ -437,6 +488,23 @@ extension FTPFileProvider {
return
}
guard let response = response else {
let badResponseError = NSError(domain: URLError.errorDomain, code: URLError.cannotParseResponse.rawValue, userInfo: nil)
completionHandler(badResponseError)
return
}
if !(response.hasPrefix("1") || !response.hasPrefix("2")) {
let spaceIndex = response.characters.index(of: " ") ?? response.startIndex
let code = Int(response.substring(to: spaceIndex).trimmingCharacters(in: .whitespacesAndNewlines)) ?? -1
let description = response.substring(from: spaceIndex).trimmingCharacters(in: .whitespacesAndNewlines)
let error = FileProviderFTPError(code: code, path: "", errorDescription: description)
self.dispatch_queue.async {
completionHandler(error)
}
return
}
}
}
}
@@ -590,3 +658,9 @@ extension FTPFileProvider {
return file
}
}
public struct FileProviderFTPError: Error {
public let code: Int
public let path: String
public let errorDescription: String?
}