diff --git a/FileProvider.podspec b/FileProvider.podspec index 36f7695..5cc1cf0 100644 --- a/FileProvider.podspec +++ b/FileProvider.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| # s.name = "FileProvider" - s.version = "0.3.3" + s.version = "0.3.4" s.summary = "NSFileManager replacement for Local and Remote (WebDAV/Dropbox/SMB2) files on iOS and MacOS." # This description is used to generate tags and improve search results. diff --git a/README.md b/README.md index 7c4bc2e..9b6017c 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Local and WebDAV providers are fully tested and can be used in production enviro - [x] **LocalFileProvider** a wrapper around `NSFileManager` with some additions like searching and reading a portion of file. - [x] **WebDAVFileProvider** WebDAV protocol is usual file transmission system on Macs. - [ ] **SMBFileProvider** SMB/CIFS and SMB2/3 are file and printer sharing protocol which is originated from IBM & Microsoft and SMB2/3 is now replacing AFP protocol on MacOS. I implemented data types and some basic functions but *main interface is not implemented yet!* -- [ ] **DropboxFileProvider** *partially implemented* +- [ ] **DropboxFileProvider** *almost completed. upload, thumbnail and search functions not implemented yet* - [ ] **FTPFileProvider** - [ ] **AmazonS3FileProvider** diff --git a/Sources/DropboxFileProvider.swift b/Sources/DropboxFileProvider.swift index 0bd0b10..cc468ab 100644 --- a/Sources/DropboxFileProvider.swift +++ b/Sources/DropboxFileProvider.swift @@ -8,30 +8,12 @@ import Foundation -public enum FileProviderDropboxErrorCode: Int { - case BadInputParameter = 400 - case ExpiredToken = 401 - case Forbidden = 403 - case Endpoint = 409 - case TooManyRequests = 429 - case InternalServer = 500 - case BadGateway = 502 -} - public struct FileProviderDropboxError: ErrorType, CustomStringConvertible { - public let code: FileProviderDropboxErrorCode + public let code: FileProviderHTTPErrorCode public let path: String public var description: String { - switch code { - case .BadInputParameter: return "Bad input parameter." - case .ExpiredToken: return "Bad or expired token. To fix this, you should re-authenticate the user." - case .Forbidden: return "Forbidden." - case .Endpoint: return "Endpoint-specific error." - case .TooManyRequests: return "Your app is making too many requests" - case .InternalServer: return "An error occurred on the Dropbox servers." - case .BadGateway: return "An error occurred on the Dropbox servers." - } + return code.description } } @@ -89,7 +71,9 @@ public class DropboxFileProvider: NSObject, FileProviderBasic { } public func contentsOfDirectoryAtPath(path: String, completionHandler: ((contents: [FileObject], error: ErrorType?) -> Void)) { - NotImplemented() + list(path) { (contents, cursor, error) in + completionHandler(contents: contents, error: error) + } } public func attributesOfItemAtPath(path: String, completionHandler: ((attributes: FileObject?, error: ErrorType?) -> Void)) { @@ -105,7 +89,7 @@ public class DropboxFileProvider: NSObject, FileProviderBasic { defer { self.delegateNotify(FileOperation.Create(path: path), error: error) } - let code = FileProviderDropboxErrorCode(rawValue: response.statusCode) + let code = FileProviderHTTPErrorCode(rawValue: response.statusCode) let dbError: FileProviderDropboxError? = code != nil ? FileProviderDropboxError(code: code!, path: path) : nil if let data = data, let jsonStr = String(data: data, encoding: NSUTF8StringEncoding) { let json = self.jsonToDictionary(jsonStr) @@ -181,7 +165,7 @@ extension DropboxFileProvider: FileProviderOperations { request.HTTPBody = dictionaryToJSON(requestDictionary)?.dataUsingEncoding(NSUTF8StringEncoding) let task = session.dataTaskWithRequest(request) { (data, response, error) in if let response = response as? NSHTTPURLResponse { - let code = FileProviderDropboxErrorCode(rawValue: response.statusCode) + let code = FileProviderHTTPErrorCode(rawValue: response.statusCode) let dbError: FileProviderDropboxError? = code != nil ? FileProviderDropboxError(code: code!, path: path ?? fromPath ?? "") : nil defer { self.delegateNotify(operation, error: error ?? dbError) @@ -219,7 +203,7 @@ extension DropboxFileProvider: FileProviderOperations { request.setValue(dictionaryToJSON(requestDictionary), forHTTPHeaderField: "Dropbox-API-Arg") let task = session.downloadTaskWithRequest(request, completionHandler: { (cacheURL, response, error) in guard let cacheURL = cacheURL, let httpResponse = response as? NSHTTPURLResponse where httpResponse.statusCode < 300 else { - let code = FileProviderDropboxErrorCode(rawValue: (response as? NSHTTPURLResponse)?.statusCode ?? -1) + let code = FileProviderHTTPErrorCode(rawValue: (response as? NSHTTPURLResponse)?.statusCode ?? -1) let dbError: FileProviderDropboxError? = code != nil ? FileProviderDropboxError(code: code!, path: path) : nil completionHandler?(error: dbError ?? error) return @@ -255,7 +239,7 @@ extension DropboxFileProvider: FileProviderReadWrite { request.setValue(dictionaryToJSON(requestDictionary), forHTTPHeaderField: "Dropbox-API-Arg") let task = session.downloadTaskWithRequest(request, completionHandler: { (cacheURL, response, error) in guard let cacheURL = cacheURL, let httpResponse = response as? NSHTTPURLResponse where httpResponse.statusCode < 300 else { - let code = FileProviderDropboxErrorCode(rawValue: (response as? NSHTTPURLResponse)?.statusCode ?? -1) + let code = FileProviderHTTPErrorCode(rawValue: (response as? NSHTTPURLResponse)?.statusCode ?? -1) let dbError: FileProviderDropboxError? = code != nil ? FileProviderDropboxError(code: code!, path: path) : nil completionHandler(contents: nil, error: dbError ?? error) return @@ -297,7 +281,7 @@ extension DropboxFileProvider: FileProviderReadWrite { } private func registerNotifcation(path: String, eventHandler: (() -> Void)) { - /* There is two ways to monitor folders chaging in Dropbox. Either using webooks + /* There is two ways to monitor folders changing in Dropbox. Either using webooks * which means you have to implement a server to translate it to push notifications * or using apiv2 list_folder/longpoll method. The second one is implemeted here. * Tough webhooks are much more efficient, longpoll is much simpler to implement! @@ -310,6 +294,54 @@ extension DropboxFileProvider: FileProviderReadWrite { } } +private extension DropboxFileProvider { + private func list(path: String, cursor: String? = nil, prevContents: [DropboxFileObject] = [], recursive: Bool = false, completionHandler: ((contents: [FileObject], cursor: String?, error: ErrorType?) -> Void)) { + var requestDictionary = [String: AnyObject]() + let url: NSURL + if let cursor = cursor { + url = NSURL(string: "https://api.dropboxapi.com/2/files/list_folder/continue")! + requestDictionary["cursor"] = cursor + } else { + url = NSURL(string: "https://api.dropboxapi.com/2/files/list_folder")! + requestDictionary["path"] = correctPath(path) + requestDictionary["recursive"] = NSNumber(bool: recursive) + } + let request = NSMutableURLRequest(URL: url) + request.HTTPMethod = "POST" + request.setValue("Bearer \(credential?.password ?? "")", forHTTPHeaderField: "Authorization") + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + request.HTTPBody = dictionaryToJSON(requestDictionary)?.dataUsingEncoding(NSUTF8StringEncoding) + let task = session.dataTaskWithRequest(request) { (data, response, error) in + var responseError: FileProviderDropboxError? + if let code = (response as? NSHTTPURLResponse)?.statusCode where code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) { + responseError = FileProviderDropboxError(code: rCode, path: path) + } + + if let data = data, let jsonStr = String(data: data, encoding: NSUTF8StringEncoding) { + let json = self.jsonToDictionary(jsonStr) + if let entries = json?["entries"] as? [AnyObject] where entries.count > 0 { + var files = prevContents + for entry in entries { + if let entry = entry as? [String: AnyObject], let file = self.mapToFileObject(entry) { + files.append(file) + } + } + let ncursor = json?["cursor"] as? String + let hasmore = (json?["has_more"] as? NSNumber)?.boolValue ?? false + if hasmore { + self.list(path, cursor: ncursor, prevContents: files, completionHandler: completionHandler) + } else { + completionHandler(contents: files, cursor: ncursor, error: responseError ?? error) + } + return + } + } + completionHandler(contents: [], cursor: nil, error: responseError ?? error) + } + task.resume() + } +} + internal extension DropboxFileProvider { private func mapToFileObject(jsonStr: String) -> DropboxFileObject? { guard let json = self.jsonToDictionary(jsonStr) else { return nil } diff --git a/Sources/WebDAVFileProvider.swift b/Sources/WebDAVFileProvider.swift index c8a7a58..873e3bc 100644 --- a/Sources/WebDAVFileProvider.swift +++ b/Sources/WebDAVFileProvider.swift @@ -8,45 +8,6 @@ import Foundation -public enum FileProviderWebDavErrorCode: Int { - case OK = 200 - case Created = 201 - case NoContent = 204 - case MultiStatus = 207 - case Forbidden = 403 - case MethodNotAllowed = 405 - case Conflict = 409 - case PreconditionFailed = 412 - case UnsupportedMediaType = 415 - case Locked = 423 - case FailedDependency = 424 - case BadGateway = 502 - case InsufficientStorage = 507 -} - -public struct FileProviderWebDavError: ErrorType, CustomStringConvertible { - public let code: FileProviderWebDavErrorCode - public let url: NSURL - - public var description: String { - switch code { - case .OK: return "OK" - case .Created: return "Created" - case .NoContent: return "No Content" - case .MultiStatus: return "" - case .Forbidden: return "Forbidden" - case .MethodNotAllowed: return "Method Not Allowed" - case .Conflict: return "Conflict" - case .PreconditionFailed: return "Precondition Failed" - case .UnsupportedMediaType: return "Unsupported Media Type" - case .Locked: return "Locked" - case .FailedDependency: return "Failed Dependency" - case .BadGateway: return "Bad Gateway" - case .InsufficientStorage: return "Insufficient Storage" - } - } -} - public final class WebDavFileObject: FileObject { public let contentType: String public let entryTag: String? @@ -102,12 +63,15 @@ public class WebDAVFileProvider: NSObject, FileProviderBasic { let url = absoluteURL(path) let request = NSMutableURLRequest(URL: url) request.HTTPMethod = "PROPFIND" - //request.setValue(baseURL?.uw_absoluteString, forHTTPHeaderField: "Host") request.setValue("1", forHTTPHeaderField: "Depth") request.setValue("text/xml; charset=\"utf-8\"", forHTTPHeaderField: "Content-Type") request.HTTPBody = "\n\n".dataUsingEncoding(NSUTF8StringEncoding) request.setValue(String(request.HTTPBody!.length), forHTTPHeaderField: "Content-Length") let task = session.dataTaskWithRequest(request) { (data, response, error) in + var responseError: FileProviderWebDavError? + if let code = (response as? NSHTTPURLResponse)?.statusCode where code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) { + responseError = FileProviderWebDavError(code: rCode, url: url) + } if let data = data { let xresponse = self.parseXMLResponse(data) var fileObjects = [WebDavFileObject]() @@ -117,31 +81,35 @@ public class WebDAVFileProvider: NSObject, FileProviderBasic { } fileObjects.append(self.mapToFileObject(attr)) } - completionHandler(contents: fileObjects, error: error) + completionHandler(contents: fileObjects, error: responseError ?? error) return } - completionHandler(contents: [], error: error) + completionHandler(contents: [], error: responseError ?? error) } task.resume() } public func attributesOfItemAtPath(path: String, completionHandler: ((attributes: FileObject?, error: ErrorType?) -> Void)) { - let request = NSMutableURLRequest(URL: absoluteURL(path)) + let url = absoluteURL(path) + let request = NSMutableURLRequest(URL: url) request.HTTPMethod = "PROPFIND" - //request.setValue(baseURL?.uw_absoluteString, forHTTPHeaderField: "Host") request.setValue("1", forHTTPHeaderField: "Depth") request.setValue("text/xml; charset=\"utf-8\"", forHTTPHeaderField: "Content-Type") request.HTTPBody = "\n\n".dataUsingEncoding(NSUTF8StringEncoding) request.setValue(String(request.HTTPBody!.length), forHTTPHeaderField: "Content-Length") let task = session.dataTaskWithRequest(request) { (data, response, error) in + var responseError: FileProviderWebDavError? + if let code = (response as? NSHTTPURLResponse)?.statusCode where code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) { + responseError = FileProviderWebDavError(code: rCode, url: url) + } if let data = data { let xresponse = self.parseXMLResponse(data) if let attr = xresponse.first { - completionHandler(attributes: self.mapToFileObject(attr), error: error) + completionHandler(attributes: self.mapToFileObject(attr), error: responseError ?? error) return } } - completionHandler(attributes: nil, error: error) + completionHandler(attributes: nil, error: responseError ?? error) } task.resume() } @@ -154,24 +122,32 @@ extension WebDAVFileProvider: FileProviderOperations { let url = absoluteURL((atPath as NSString).stringByAppendingPathComponent(folderName) + "/") let request = NSMutableURLRequest(URL: url) request.HTTPMethod = "MKCOL" - //request.setValue(baseURL?.uw_absoluteString, forHTTPHeaderField: "Host") let task = session.dataTaskWithRequest(request) { (data, response, error) in - if let response = response as? NSHTTPURLResponse, let code = FileProviderWebDavErrorCode(rawValue: response.statusCode) where code != .OK { + var responseError: FileProviderWebDavError? + if let code = (response as? NSHTTPURLResponse)?.statusCode where code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) { + responseError = FileProviderWebDavError(code: rCode, url: url) + } + if let response = response as? NSHTTPURLResponse, let code = FileProviderHTTPErrorCode(rawValue: response.statusCode) where code != .OK { completionHandler?(error: FileProviderWebDavError(code: code, url: url)) return } - completionHandler?(error: error) - self.delegateNotify(.Create(path: (atPath as NSString).stringByAppendingPathComponent(folderName) + "/"), error: error) + completionHandler?(error: responseError ?? error) + self.delegateNotify(.Create(path: (atPath as NSString).stringByAppendingPathComponent(folderName) + "/"), error: responseError ?? error) } task.resume() } public func createFile(fileAttribs: FileObject, atPath path: String, contents data: NSData?, completionHandler: SimpleCompletionHandler) { - let request = NSMutableURLRequest(URL: absoluteURL(path)) + let url = absoluteURL(path) + let request = NSMutableURLRequest(URL: url) request.HTTPMethod = "PUT" let task = session.uploadTaskWithRequest(request, fromData: data) { (data, response, error) in - completionHandler?(error: error) - self.delegateNotify(.Create(path: (path as NSString).stringByAppendingPathComponent(fileAttribs.name)), error: error) + var responseError: FileProviderWebDavError? + if let code = (response as? NSHTTPURLResponse)?.statusCode where code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) { + responseError = FileProviderWebDavError(code: rCode, url: url) + } + completionHandler?(error: responseError ?? error) + self.delegateNotify(.Create(path: (path as NSString).stringByAppendingPathComponent(fileAttribs.name)), error: responseError ?? error) } task.taskDescription = self.dictionaryToJSON(["type": "Create", "source": (path as NSString).stringByAppendingPathComponent(fileAttribs.name)]) task.resume() @@ -193,13 +169,12 @@ extension WebDAVFileProvider: FileProviderOperations { } else { request.HTTPMethod = "COPY" } - //request.setValue(baseURL?.uw_absoluteString, forHTTPHeaderField: "Host") request.setValue(absoluteURL(path).uw_absoluteString, forHTTPHeaderField: "Destination") if !overwrite { request.setValue("F", forHTTPHeaderField: "Overwrite") } let task = session.dataTaskWithRequest(request) { (data, response, error) in - if let response = response as? NSHTTPURLResponse, let code = FileProviderWebDavErrorCode(rawValue: response.statusCode) { + if let response = response as? NSHTTPURLResponse, let code = FileProviderHTTPErrorCode(rawValue: response.statusCode) { defer { let op = move ? FileOperation.Move(source: path, destination: toPath) : .Copy(source: path, destination: toPath) self.delegateNotify(op, error: error) @@ -223,9 +198,8 @@ extension WebDAVFileProvider: FileProviderOperations { let url = absoluteURL(path) let request = NSMutableURLRequest(URL: url) request.HTTPMethod = "DELETE" - //request.setValue(baseURL?.uw_absoluteString, forHTTPHeaderField: "Host") let task = session.dataTaskWithRequest(request) { (data, response, error) in - if let response = response as? NSHTTPURLResponse, let code = FileProviderWebDavErrorCode(rawValue: response.statusCode) { + if let response = response as? NSHTTPURLResponse, let code = FileProviderHTTPErrorCode(rawValue: response.statusCode) { defer { self.delegateNotify(.Remove(path: path), error: error) } @@ -245,19 +219,29 @@ extension WebDAVFileProvider: FileProviderOperations { } public func copyLocalFileToPath(localFile: NSURL, toPath: String, completionHandler: SimpleCompletionHandler) { - let request = NSMutableURLRequest(URL: absoluteURL(toPath)) + let url = absoluteURL(toPath) + let request = NSMutableURLRequest(URL: url) request.HTTPMethod = "PUT" let task = session.uploadTaskWithRequest(request, fromFile: localFile) { (data, response, error) in - completionHandler?(error: error) - self.delegateNotify(.Move(source: localFile.uw_absoluteString, destination: toPath), error: error) + var responseError: FileProviderWebDavError? + if let code = (response as? NSHTTPURLResponse)?.statusCode where code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) { + responseError = FileProviderWebDavError(code: rCode, url: url) + } + completionHandler?(error: responseError ?? error) + self.delegateNotify(.Move(source: localFile.uw_absoluteString, destination: toPath), error: responseError ?? error) } task.taskDescription = self.dictionaryToJSON(["type": "Copy", "source": localFile.uw_absoluteString, "dest": toPath]) task.resume() } public func copyPathToLocalFile(path: String, toLocalURL: NSURL, completionHandler: SimpleCompletionHandler) { - let request = NSMutableURLRequest(URL: absoluteURL(path)) + let url = absoluteURL(path) + let request = NSMutableURLRequest(URL: url) let task = session.downloadTaskWithRequest(request) { (sourceFileURL, response, error) in + var responseError: FileProviderWebDavError? + if let code = (response as? NSHTTPURLResponse)?.statusCode where code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) { + responseError = FileProviderWebDavError(code: rCode, url: url) + } if let sourceFileURL = sourceFileURL { do { try NSFileManager.defaultManager().copyItemAtURL(sourceFileURL, toURL: toLocalURL) @@ -266,7 +250,7 @@ extension WebDAVFileProvider: FileProviderOperations { return } } - completionHandler?(error: error) + completionHandler?(error: responseError ?? error) } task.taskDescription = self.dictionaryToJSON(["type": "Copy", "source": path, "dest": toLocalURL.uw_absoluteString]) task.resume() @@ -279,7 +263,8 @@ extension WebDAVFileProvider: FileProviderReadWrite { } public func contentsAtPath(path: String, offset: Int64, length: Int, completionHandler: ((contents: NSData?, error: ErrorType?) -> Void)) { - let request = NSMutableURLRequest(URL: absoluteURL(path)) + let url = absoluteURL(path) + let request = NSMutableURLRequest(URL: url) request.HTTPMethod = "GET" if length > 0 { request.setValue("bytes=\(offset)-\(offset + length)", forHTTPHeaderField: "Range") @@ -287,7 +272,11 @@ extension WebDAVFileProvider: FileProviderReadWrite { request.setValue("bytes=\(offset)-", forHTTPHeaderField: "Range") } let task = session.dataTaskWithRequest(request) { (data, response, error) in - completionHandler(contents: data, error: error) + var responseError: FileProviderWebDavError? + if let code = (response as? NSHTTPURLResponse)?.statusCode where code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) { + responseError = FileProviderWebDavError(code: rCode, url: url) + } + completionHandler(contents: data, error: responseError ?? error) } task.resume() } @@ -298,16 +287,20 @@ extension WebDAVFileProvider: FileProviderReadWrite { let request = NSMutableURLRequest(URL: url) request.HTTPMethod = "PUT" let task = session.uploadTaskWithRequest(request, fromData: data) { (data, response, error) in + var responseError: FileProviderWebDavError? + if let code = (response as? NSHTTPURLResponse)?.statusCode where code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) { + responseError = FileProviderWebDavError(code: rCode, url: self.absoluteURL(path)) + } defer { - self.delegateNotify(.Modify(path: path), error: error) + self.delegateNotify(.Modify(path: path), error: responseError ?? error) + } + if let error = error { + completionHandler?(error: error) + return } if atomically { 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 - completionHandler?(error: error) - } } task.taskDescription = self.dictionaryToJSON(["type": "Modify", "source": path]) task.resume() @@ -317,13 +310,16 @@ extension WebDAVFileProvider: FileProviderReadWrite { let url = absoluteURL(path) let request = NSMutableURLRequest(URL: url) request.HTTPMethod = "PROPFIND" - //request.setValue(baseURL?.uw_absoluteString, forHTTPHeaderField: "Host") //request.setValue("1", forHTTPHeaderField: "Depth") request.setValue("text/xml; charset=\"utf-8\"", forHTTPHeaderField: "Content-Type") request.HTTPBody = "\n\n".dataUsingEncoding(NSUTF8StringEncoding) request.setValue(String(request.HTTPBody!.length), forHTTPHeaderField: "Content-Length") let task = session.dataTaskWithRequest(request) { (data, response, error) in // FIXME: paginating results + var responseError: FileProviderWebDavError? + if let code = (response as? NSHTTPURLResponse)?.statusCode where code >= 300, let rCode = FileProviderHTTPErrorCode(rawValue: code) { + responseError = FileProviderWebDavError(code: rCode, url: url) + } if let data = data { let xresponse = self.parseXMLResponse(data) var fileObjects = [WebDavFileObject]() @@ -335,10 +331,10 @@ extension WebDAVFileProvider: FileProviderReadWrite { fileObjects.append(fileObject) foundItemHandler?(fileObject) } - completionHandler(files: fileObjects, error: error) + completionHandler(files: fileObjects, error: responseError ?? error) return } - completionHandler(files: [], error: error) + completionHandler(files: [], error: responseError ?? error) } task.resume() } @@ -508,10 +504,155 @@ extension WebDAVFileProvider: NSURLSessionDataDelegate, NSURLSessionDownloadDele } public func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { - completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential) + let deposition: NSURLSessionAuthChallengeDisposition = credential != nil ? .UseCredential : .PerformDefaultHandling + completionHandler(deposition, credential) } public func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { - completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential) + let deposition: NSURLSessionAuthChallengeDisposition = credential != nil ? .UseCredential : .PerformDefaultHandling + completionHandler(deposition, credential) + } +} + +public struct FileProviderWebDavError: ErrorType, CustomStringConvertible { + public let code: FileProviderHTTPErrorCode + public let url: NSURL + + public var description: String { + return code.description + } +} + +public enum FileProviderHTTPErrorCode: Int { + case OK = 200 + case Created = 201 + case Accepted = 202 + case NonAuthoritativeInformation = 203 + case NoContent = 204 + case ResetContent = 205 + case PartialContent = 206 + case MultiStatus = 207 + case AlreadyReported = 208 + case IMUsed = 226 + case MultipleChoices = 300 + case MovedPermanently = 301 + case Found = 302 + case SeeOther = 303 + case NotModified = 304 + case UseProxy = 305 + case TemporaryRedirect = 307 + case PermanentRedirect = 308 + case BadRequest = 400 + case Unauthorized = 401 + case PaymentRequired = 402 + case Forbidden = 403 + case NotFound = 404 + case MethodNotAllowed = 405 + case NotAcceptable = 406 + case ProxyAuthenticationRequired = 407 + case RequestTimeout = 408 + case Conflict = 409 + case Gone = 410 + case LengthRequired = 411 + case PreconditionFailed = 412 + case PayloadTooLarge = 413 + case URITooLong = 414 + case UnsupportedMediaType = 415 + case RangeNotSatisfiable = 416 + case ExpectationFailed = 417 + case MisdirectedRequest = 421 + case UnprocessableEntity = 422 + case Locked = 423 + case FailedDependency = 424 + case UpgradeRequired = 426 + case PreconditionRequired = 428 + case TooManyRequests = 429 + case RequestHeaderFieldsTooLarge = 431 + case UnavailableForLegalReasons = 451 + case InternalServerError = 500 + case BadGateway = 502 + case ServiceUnavailable = 503 + case GatewayTimeout = 504 + case HTTPVersionNotSupported = 505 + case VariantlsoNegotiates = 506 + case InsufficientStorage = 507 + case LoopDetected = 508 + case NotExtended = 510 + case NetworkAuthenticationRequired = 511 + + public var description: String { + switch self.rawValue { + case 100: return "Continue" + case 101: return "Switching Protocols" + case 102: return "Processing" + case 200: return "OK" + case 201: return "Created" + case 202: return "Accepted" + case 203: return "Non-Authoritative Information" + case 204: return "No Content" + case 205: return "Reset Content" + case 206: return "Partial Content" + case 207: return "Multi-Status" + case 208: return "Already Reported" + case 226: return "IM Used" + case 300: return "Multiple Choices" + case 301: return "Moved Permanently" + case 302: return "Found" + case 303: return "See Other" + case 304: return "Not Modified" + case 305: return "Use Proxy" + case 307: return "Temporary Redirect" + case 308: return "Permanent Redirect" + case 400: return "Bad Request" + case 401: return "Unauthorized/Expired Session" + case 402: return "Payment Required" + case 403: return "Forbidden" + case 404: return "Not Found" + case 405: return "Method Not Allowed" + case 406: return "Not Acceptable" + case 407: return "Proxy Authentication Required" + case 408: return "Request Timeout" + case 409: return "Conflict" + case 410: return "Gone" + case 411: return "Length Required" + case 412: return "Precondition Failed" + case 413: return "Payload Too Large" + case 414: return "URI Too Long" + case 415: return "Unsupported Media Type" + case 416: return "Range Not Satisfiable" + case 417: return "Expectation Failed" + case 421: return "Misdirected Request" + case 422: return "Unprocessable Entity" + case 423: return "Locked" + case 424: return "Failed Dependency" + case 426: return "Upgrade Required" + case 428: return "Precondition Required" + case 429: return "Too Many Requests" + case 431: return "Request Header Fields Too Large" + case 451: return "Unavailable For Legal Reasons" + case 500: return "Internal Server Error" + case 501: return "Not Implemented" + case 502: return "Bad Gateway" + case 503: return "Service Unavailable" + case 504: return "Gateway Timeout" + case 505: return "HTTP Version Not Supported" + case 506: return "Variant Also Negotiates" + case 507: return "Insufficient Storage" + case 508: return "Loop Detected" + case 510: return "Not Extended" + case 511: return "Network Authentication Required" + default: return typeDescription + } + } + + public var typeDescription: String { + switch self.rawValue { + case 100...199: return "Informational" + case 200...299: return "Success" + case 300...399: return "Redirection" + case 400...499: return "Client Error" + case 500...599: return "Server Error" + default: return "Server Error" + } } } \ No newline at end of file