0001 // 0002 // Request.swift 0003 // SwiftHTTP 0004 // 0005 // Created by Dalton Cherry on 8/16/15. 0006 // Copyright © 2015 vluxe. All rights reserved. 0007 // 0008 0009 import Foundation 0010 0011 0012 extension String { 0013 /** 0014 A simple extension to the String object to encode it for web request. 0015 0016 :returns: Encoded version of of string it was called as. 0017 */ 0018 var escaped: String? { 0019 let set = NSMutableCharacterSet() 0020 set.formUnionWithCharacterSet(NSCharacterSet.URLQueryAllowedCharacterSet()) 0021 set.removeCharactersInString("[].:/?&=;+!@#$()',*\"") // remove the HTTP ones from the set. 0022 return self.stringByAddingPercentEncodingWithAllowedCharacters(set) 0023 } 0024 } 0025 0026 /** 0027 The standard HTTP Verbs 0028 */ 0029 public enum HTTPVerb
Request.swift:76 if let v = value.escaped {Request.swift:78 if let escapedKey = k.escaped {Request.swift:293 var str = "Content-Disposition: form-data; name=\"\(name.escaped!)\"": String { 0030 case GET
Operation.swift:385 public class func New(url: String, method: HTTPVerb, parameters: HTTPParameterProtocol? = nil, headers: [String:String]? = nil, requestSerializer: HTTPSerializeProtocol = HTTPParameterSerializer()) throws -> HTTP {Request.swift:196 if let v = HTTPVerb(rawValue: HTTPMethod) {Request.swift:191 public var verb: HTTPVerb {= "GET" 0031 case POST
Operation.swift:343 return try HTTP.New(url, method: .GET, parameters: parameters, headers: headers, requestSerializer: requestSerializer)Request.swift:328 if verb == .GET || verb == .HEAD || verb == .DELETE {= "POST" 0032 case PUT
Operation.swift:364 return try HTTP.New(url, method: .POST, parameters: parameters, headers: headers, requestSerializer: requestSerializer)= "PUT" 0033 case HEAD
Operation.swift:372 return try HTTP.New(url, method: .PUT, parameters: parameters, headers: headers, requestSerializer: requestSerializer)= "HEAD" 0034 case DELETE
Operation.swift:350 return try HTTP.New(url, method: .HEAD, parameters: parameters, headers: headers, requestSerializer: requestSerializer)Request.swift:328 if verb == .GET || verb == .HEAD || verb == .DELETE {= "DELETE" 0035 case PATCH
Operation.swift:357 return try HTTP.New(url, method: .DELETE, parameters: parameters, headers: headers, requestSerializer: requestSerializer)Request.swift:328 if verb == .GET || verb == .HEAD || verb == .DELETE {= "PATCH" 0036 case OPTIONS = "OPTIONS" 0037 case TRACE = "TRACE" 0038 case CONNECT = "CONNECT" 0039 case UNKNOWN
Operation.swift:379 return try HTTP.New(url, method: .PATCH, parameters: parameters, headers: headers, requestSerializer: requestSerializer)= "UNKNOWN" 0040 } 0041 0042 /** 0043 This is used to create key/value pairs of the parameters 0044 */ 0045 public struct HTTPPair
Request.swift:199 return .UNKNOWN{ 0046 var key
Request.swift:103 func createPairs(key: String?) -> Array<HTTPPair>Request.swift:113 public func createPairs(key: String?) -> Array<HTTPPair> {Request.swift:114 var collect = Array<HTTPPair>()Request.swift:123 collect.append(HTTPPair(key: useKey, value: nestedVal))Request.swift:139 public func createPairs(key: String?) -> Array<HTTPPair> {Request.swift:140 var collect = Array<HTTPPair>()Request.swift:149 collect.append(HTTPPair(key: useKey, value: nestedVal))Request.swift:165 public func createPairs(key: String?) -> Array<HTTPPair> {Request.swift:166 var collect = Array<HTTPPair>()Request.swift:167 collect.append(HTTPPair(key: key, value: self)): String? 0047 let storeVal
Request.swift:52 self.key = keyRequest.swift:77 if let k = key {Request.swift:272 guard let key = pair.key else { continue } //this won't happen, but just to properly unwrap: AnyObject 0048 /** 0049 Create the object with a possible key and a value 0050 */ 0051 init
Request.swift:53 self.storeVal = valueRequest.swift:59 return storeVal as? UploadRequest.swift:65 if let v = storeVal as? String {Request.swift:67 } else if let v = storeVal.description {(key: String?, value: AnyObject) { 0052 self.key = key 0053 self.storeVal = value 0054 } 0055 /** 0056 Computed property of the string representation of the storedVal 0057 */ 0058 var upload
Request.swift:123 collect.append(HTTPPair(key: useKey, value: nestedVal))Request.swift:149 collect.append(HTTPPair(key: useKey, value: nestedVal))Request.swift:167 collect.append(HTTPPair(key: key, value: self)): Upload? { 0059 return storeVal as? Upload 0060 } 0061 /** 0062 Computed property of the string representation of the storedVal 0063 */ 0064 var value
Request.swift:274 if let upload = pair.upload {Request.swift:341 if let _ = pair.upload {: String { 0065 if let v = storeVal as? String { 0066 return v 0067 } else if let v = storeVal.description { 0068 return v 0069 } 0070 return "" 0071 } 0072 /** 0073 Computed property of the string representation of the storedVal escaped for URLs 0074 */ 0075 var escapedValue
Request.swift:76 if let v = value.escaped {Request.swift:280 let str = "\(multiFormHeader(key, fileName: nil, type: nil, multiCRLF: multiCRLF))\(pair.value)": String { 0076 if let v = value.escaped { 0077 if let k = key { 0078 if let escapedKey = k.escaped { 0079 return "\(escapedKey)=\(v)" 0080 } 0081 } 0082 return v 0083 } 0084 return "" 0085 } 0086 } 0087 0088 /** 0089 Enum used to describe what kind of Parameter is being interacted with. 0090 This allows us to only support an Array or Dictionary and avoid having to use AnyObject 0091 */ 0092 public enum HTTPParamType
Request.swift:233 return pair.escapedValueRequest.swift:253 return pair.escapedValue{ 0093 case Array
Request.swift:102 func paramType() -> HTTPParamTypeRequest.swift:110 public func paramType() -> HTTPParamType {Request.swift:135 public func paramType() -> HTTPParamType {Request.swift:161 public func paramType() -> HTTPParamType {0094 case Dictionary
Request.swift:136 return .Array0095 case Upload
Request.swift:111 return .Dictionary0096 } 0097 0098 /** 0099 This protocol is used to make the dictionary and array serializable into key/value pairs. 0100 */ 0101 public protocol HTTPParameterProtocol
Request.swift:162 return .Upload{ 0102 func paramType() -> HTTPParamType 0103 func createPairs
Operation.swift:25 func serialize(request: NSMutableURLRequest, parameters: HTTPParameterProtocol) throwsOperation.swift:33 public func serialize(request: NSMutableURLRequest, parameters: HTTPParameterProtocol) throws {Operation.swift:43 public func serialize(request: NSMutableURLRequest, parameters: HTTPParameterProtocol) throws {Operation.swift:341 public class func GET(url: String, parameters: HTTPParameterProtocol? = nil, headers: [String:String]? = nil,Operation.swift:349 public class func HEAD(url: String, parameters: HTTPParameterProtocol? = nil, headers: [String:String]? = nil, requestSerializer: HTTPSerializeProtocol = HTTPParameterSerializer()) throws -> HTTP {Operation.swift:356 public class func DELETE(url: String, parameters: HTTPParameterProtocol? = nil, headers: [String:String]? = nil, requestSerializer: HTTPSerializeProtocol = HTTPParameterSerializer()) throws -> HTTP {Operation.swift:363 public class func POST(url: String, parameters: HTTPParameterProtocol? = nil, headers: [String:String]? = nil, requestSerializer: HTTPSerializeProtocol = HTTPParameterSerializer()) throws -> HTTP {Operation.swift:370 public class func PUT(url: String, parameters: HTTPParameterProtocol? = nil, headers: [String:String]? = nil,Operation.swift:378 public class func PATCH(url: String, parameters: HTTPParameterProtocol? = nil, headers: [String:String]? = nil, requestSerializer: HTTPSerializeProtocol = HTTPParameterSerializer()) throws -> HTTP {Operation.swift:385 public class func New(url: String, method: HTTPVerb, parameters: HTTPParameterProtocol? = nil, headers: [String:String]? = nil, requestSerializer: HTTPSerializeProtocol = HTTPParameterSerializer()) throws -> HTTP {Request.swift:109 extension Dictionary: HTTPParameterProtocol {Request.swift:134 extension Array: HTTPParameterProtocol {Request.swift:160 extension Upload: HTTPParameterProtocol {Request.swift:217 public func appendParameters(parameters: HTTPParameterProtocol) throws {Request.swift:231 public func appendParametersAsQueryString(parameters: HTTPParameterProtocol) {Request.swift:245 public func appendParametersAsUrlEncoding(parameters: HTTPParameterProtocol) {Request.swift:262 public func appendParametersAsMultiPartFormData(parameters: HTTPParameterProtocol) throws {Request.swift:310 public func appendParametersAsJSON(parameters: HTTPParameterProtocol) throws {Request.swift:339 guard let params = parameters as? HTTPParameterProtocol else { return false }(key: String?) -> Array<HTTPPair> 0104 } 0105 0106 /** 0107 Support for the Dictionary type as an HTTPParameter. 0108 */ 0109 extension Dictionary: HTTPParameterProtocol { 0110 public func paramType() -> HTTPParamType { 0111 return .Dictionary 0112 } 0113 public func createPairs
Request.swift:232 let queryString = parameters.createPairs(nil).map({ (pair) inRequest.swift:252 let queryString = parameters.createPairs(nil).map({ (pair) inRequest.swift:271 for pair in parameters.createPairs(nil) {Request.swift:340 for pair in params.createPairs(nil) {(key: String?) -> Array<HTTPPair> { 0114 var collect = Array<HTTPPair>() 0115 for (k, v) in self { 0116 if let nestedKey = k as? String, let nestedVal = v as? AnyObject { 0117 let useKey = key != nil ? "\(key!)[\(nestedKey)]" : nestedKey 0118 if let subParam = nestedVal as? Dictionary { //as? HTTPParameterProtocol <- bug? should work. 0119 collect.appendContentsOf(subParam.createPairs(useKey)) 0120 } else if let subParam = nestedVal as? Array<AnyObject> { 0121 collect.appendContentsOf(subParam.createPairs(useKey)) 0122 } else { 0123 collect.append(HTTPPair(key: useKey, value: nestedVal)) 0124 } 0125 } 0126 } 0127 return collect 0128 } 0129 } 0130 0131 /** 0132 Support for the Array type as an HTTPParameter. 0133 */ 0134 extension Array: HTTPParameterProtocol { 0135 public func paramType() -> HTTPParamType { 0136 return .Array 0137 } 0138 0139 public func createPairs
Request.swift:119 collect.appendContentsOf(subParam.createPairs(useKey))Request.swift:145 collect.appendContentsOf(subParam.createPairs(useKey))(key: String?) -> Array<HTTPPair> { 0140 var collect = Array<HTTPPair>() 0141 for v in self { 0142 if let nestedVal = v as? AnyObject { 0143 let useKey = key != nil ? "\(key!)[]" : key 0144 if let subParam = nestedVal as? Dictionary<String, AnyObject> { 0145 collect.appendContentsOf(subParam.createPairs(useKey)) 0146 } else if let subParam = nestedVal as? Array<AnyObject> { 0147 collect.appendContentsOf(subParam.createPairs(useKey)) 0148 } else { 0149 collect.append(HTTPPair(key: useKey, value: nestedVal)) 0150 } 0151 } 0152 } 0153 return collect 0154 } 0155 } 0156 0157 /** 0158 Support for the Upload type as an HTTPParameter. 0159 */ 0160 extension Upload: HTTPParameterProtocol { 0161 public func paramType() -> HTTPParamType { 0162 return .Upload 0163 } 0164 0165 public func createPairs(key: String?) -> Array<HTTPPair> { 0166 var collect = Array<HTTPPair>() 0167 collect.append(HTTPPair(key: key, value: self)) 0168 return collect 0169 } 0170 } 0171 0172 /** 0173 Adds convenience methods to NSMutableURLRequest to make using it with HTTP much simpler. 0174 */ 0175 extension NSMutableURLRequest { 0176 /** 0177 Convenience init to allow init with a string. 0178 -parameter urlString: The string representation of a URL to init with. 0179 */ 0180 public convenience init
Request.swift:121 collect.appendContentsOf(subParam.createPairs(useKey))Request.swift:147 collect.appendContentsOf(subParam.createPairs(useKey))?(urlString: String) { 0181 if let url = NSURL(string: urlString) { 0182 self.init(URL: url) 0183 } else { 0184 return nil 0185 } 0186 } 0187 0188 /** 0189 Convenience method to avoid having to use strings and allow using an enum 0190 */ 0191 public var verb
Operation.swift:386 guard let req = NSMutableURLRequest(urlString: url) else { throw HTTPOptError.InvalidRequest }: HTTPVerb { 0192 set { 0193 HTTPMethod = newValue.rawValue 0194 } 0195 get { 0196 if let v = HTTPVerb(rawValue: HTTPMethod) { 0197 return v 0198 } 0199 return .UNKNOWN 0200 } 0201 } 0202 0203 /** 0204 Used to update the content type in the HTTP header as needed 0205 */ 0206 var contentTypeKey
Operation.swift:390 req.verb = methodRequest.swift:328 if verb == .GET || verb == .HEAD || verb == .DELETE {Request.swift:328 if verb == .GET || verb == .HEAD || verb == .DELETE {Request.swift:328 if verb == .GET || verb == .HEAD || verb == .DELETE {: String { 0207 return "Content-Type" 0208 } 0209 0210 /** 0211 append the parameters using the standard HTTP Query model. 0212 This is parameters in the query string of the url (e.g. ?first=one&second=two for GET, HEAD, DELETE. 0213 It uses 'application/x-www-form-urlencoded' for the content type of POST/PUT requests that don't contains files. 0214 If it contains a file it uses `multipart/form-data` for the content type. 0215 -parameter parameters: The container (array or dictionary) to convert and append to the URL or Body 0216 */ 0217 public func appendParameters
Request.swift:246 if valueForHTTPHeaderField(contentTypeKey) == nil {Request.swift:249 forHTTPHeaderField:contentTypeKey)Request.swift:264 if valueForHTTPHeaderField(contentTypeKey) == nil {Request.swift:266 forHTTPHeaderField:contentTypeKey)Request.swift:320 setValue("application/json; charset=\(charset)", forHTTPHeaderField: contentTypeKey)(parameters: HTTPParameterProtocol) throws { 0218 if isURIParam() { 0219 appendParametersAsQueryString(parameters) 0220 } else if containsFile(parameters) { 0221 try appendParametersAsMultiPartFormData(parameters) 0222 } else { 0223 appendParametersAsUrlEncoding(parameters) 0224 } 0225 } 0226 0227 /** 0228 append the parameters as a HTTP Query string. (e.g. domain.com?first=one&second=two) 0229 -parameter parameters: The container (array or dictionary) to convert and append to the URL 0230 */ 0231 public func appendParametersAsQueryString
Operation.swift:34 try request.appendParameters(parameters)(parameters: HTTPParameterProtocol) { 0232 let queryString = parameters.createPairs(nil).map({ (pair) in 0233 return pair.escapedValue 0234 }).joinWithSeparator("&") 0235 if let u = self.URL where queryString.characters.count > 0 { 0236 let para = u.query != nil ? "&" : "?" 0237 self.URL = NSURL(string: "\(u.absoluteString)\(para)\(queryString)") 0238 } 0239 } 0240 0241 /** 0242 append the parameters as a url encoded string. (e.g. in the body of the request as: first=one&second=two) 0243 -parameter parameters: The container (array or dictionary) to convert and append to the HTTP body 0244 */ 0245 public func appendParametersAsUrlEncoding
Request.swift:219 appendParametersAsQueryString(parameters)Request.swift:312 appendParametersAsQueryString(parameters)(parameters: HTTPParameterProtocol) { 0246 if valueForHTTPHeaderField(contentTypeKey) == nil { 0247 let charset = CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)) 0248 setValue("application/x-www-form-urlencoded; charset=\(charset)", 0249 forHTTPHeaderField:contentTypeKey) 0250 0251 } 0252 let queryString = parameters.createPairs(nil).map({ (pair) in 0253 return pair.escapedValue 0254 }).joinWithSeparator("&") 0255 HTTPBody = queryString.dataUsingEncoding(NSUTF8StringEncoding) 0256 } 0257 0258 /** 0259 append the parameters as a multpart form body. This is the type normally used for file uploads. 0260 -parameter parameters: The container (array or dictionary) to convert and append to the HTTP body 0261 */ 0262 public func appendParametersAsMultiPartFormData
Request.swift:223 appendParametersAsUrlEncoding(parameters)(parameters: HTTPParameterProtocol) throws { 0263 let boundary = "Boundary+\(arc4random())\(arc4random())" 0264 if valueForHTTPHeaderField(contentTypeKey) == nil { 0265 setValue("multipart/form-data; boundary=\(boundary)", 0266 forHTTPHeaderField:contentTypeKey) 0267 } 0268 let mutData = NSMutableData() 0269 let multiCRLF = "\r\n" 0270 mutData.appendData("--\(boundary)".dataUsingEncoding(NSUTF8StringEncoding)!) 0271 for pair in parameters.createPairs(nil) { 0272 guard let key = pair.key else { continue } //this won't happen, but just to properly unwrap 0273 mutData.appendData("\(multiCRLF)".dataUsingEncoding(NSUTF8StringEncoding)!) 0274 if let upload = pair.upload { 0275 let data = try upload.getData() 0276 mutData.appendData(multiFormHeader(key, fileName: upload.fileName, 0277 type: upload.mimeType, multiCRLF: multiCRLF).dataUsingEncoding(NSUTF8StringEncoding)!) 0278 mutData.appendData(data) 0279 } else { 0280 let str = "\(multiFormHeader(key, fileName: nil, type: nil, multiCRLF: multiCRLF))\(pair.value)" 0281 mutData.appendData(str.dataUsingEncoding(NSUTF8StringEncoding)!) 0282 } 0283 mutData.appendData("\(multiCRLF)--\(boundary)".dataUsingEncoding(NSUTF8StringEncoding)!) 0284 } 0285 mutData.appendData("--\(multiCRLF)".dataUsingEncoding(NSUTF8StringEncoding)!) 0286 HTTPBody = mutData 0287 } 0288 0289 /** 0290 Helper method to create the multipart form data 0291 */ 0292 func multiFormHeader
Request.swift:221 try appendParametersAsMultiPartFormData(parameters)(name: String, fileName: String?, type: String?, multiCRLF: String) -> String { 0293 var str = "Content-Disposition: form-data; name=\"\(name.escaped!)\"" 0294 if let name = fileName { 0295 str += "; filename=\"\(name)\"" 0296 } 0297 str += multiCRLF 0298 if let t = type { 0299 str += "Content-Type: \(t)\(multiCRLF)" 0300 } 0301 str += multiCRLF 0302 return str 0303 } 0304 0305 0306 /** 0307 send the parameters as a body of JSON 0308 -parameter parameters: The container (array or dictionary) to convert and append to the URL or Body 0309 */ 0310 public func appendParametersAsJSON
Request.swift:276 mutData.appendData(multiFormHeader(key, fileName: upload.fileName,Request.swift:280 let str = "\(multiFormHeader(key, fileName: nil, type: nil, multiCRLF: multiCRLF))\(pair.value)"(parameters: HTTPParameterProtocol) throws { 0311 if isURIParam() { 0312 appendParametersAsQueryString(parameters) 0313 } else { 0314 do { 0315 HTTPBody = try NSJSONSerialization.dataWithJSONObject(parameters as! AnyObject, options: NSJSONWritingOptions()) 0316 } catch let error { 0317 throw error 0318 } 0319 let charset = CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)) 0320 setValue("application/json; charset=\(charset)", forHTTPHeaderField: contentTypeKey) 0321 } 0322 } 0323 0324 /** 0325 Check if the request requires the parameters to be appended to the URL 0326 */ 0327 public func isURIParam
Operation.swift:44 try request.appendParametersAsJSON(parameters)() -> Bool { 0328 if verb == .GET || verb == .HEAD || verb == .DELETE { 0329 return true 0330 } 0331 return false 0332 } 0333 0334 /** 0335 check if the parameters contain a file object within them 0336 -parameter parameters: The parameters to search through for an upload object 0337 */ 0338 public func containsFile
Request.swift:218 if isURIParam() {Request.swift:311 if isURIParam() {(parameters: Any) -> Bool { 0339 guard let params = parameters as? HTTPParameterProtocol else { return false } 0340 for pair in params.createPairs(nil) { 0341 if let _ = pair.upload { 0342 return true 0343 } 0344 } 0345 return false 0346 } 0347 } 0348
Request.swift:220 } else if containsFile(parameters) {