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
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? { 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
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 {
: String { 0030 case GET
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 {
= "GET" 0031 case POST
Operation.swift:364
        return try HTTP.New(url, method: .POST, parameters: parameters, headers: headers, requestSerializer: requestSerializer)
= "POST" 0032 case PUT
Operation.swift:372
        return try HTTP.New(url, method: .PUT, parameters: parameters, headers: headers, requestSerializer: requestSerializer)
= "PUT" 0033 case HEAD
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 {
= "HEAD" 0034 case DELETE
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 {
= "DELETE" 0035 case PATCH
Operation.swift:379
        return try HTTP.New(url, method: .PATCH, parameters: parameters, headers: headers, requestSerializer: requestSerializer)
= "PATCH" 0036 case OPTIONS = "OPTIONS" 0037 case TRACE = "TRACE" 0038 case CONNECT = "CONNECT" 0039 case UNKNOWN
Request.swift:199
            return .UNKNOWN
= "UNKNOWN" 0040 } 0041 0042 /** 0043 This is used to create key/value pairs of the parameters 0044 */ 0045 public struct HTTPPair
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))
{ 0046 var key
Request.swift:52
        self.key = key
Request.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
: String? 0047 let storeVal
Request.swift:53
        self.storeVal = value
Request.swift:59
        return storeVal as? Upload
Request.swift:65
        if let v = storeVal as? String {
Request.swift:67
        } else if let v = storeVal.description {
: AnyObject 0048 /** 0049 Create the object with a possible key and a value 0050 */ 0051 init
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))
(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:274
            if let upload = pair.upload {
Request.swift:341
            if let _ = pair.upload {
: Upload? { 0059 return storeVal as? Upload 0060 } 0061 /** 0062 Computed property of the string representation of the storedVal 0063 */ 0064 var value
Request.swift:76
        if let v = value.escaped {
Request.swift:280
                let str = "\(multiFormHeader(key, fileName: nil, type: nil, multiCRLF: multiCRLF))\(pair.value)"
: 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:233
            return pair.escapedValue
Request.swift:253
            return pair.escapedValue
: 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:102
    func paramType() -> HTTPParamType
Request.swift:110
    public func paramType() -> HTTPParamType {
Request.swift:135
    public func paramType() -> HTTPParamType {
Request.swift:161
    public func paramType() -> HTTPParamType {
{ 0093 case Array
Request.swift:136
        return .Array
0094 case Dictionary
Request.swift:111
        return .Dictionary
0095 case Upload
Request.swift:162
        return .Upload
0096 } 0097 0098 /** 0099 This protocol is used to make the dictionary and array serializable into key/value pairs. 0100 */ 0101 public protocol HTTPParameterProtocol
Operation.swift:25
    func serialize(request: NSMutableURLRequest, parameters: HTTPParameterProtocol) throws
Operation.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 }
{ 0102 func paramType() -> HTTPParamType 0103 func createPairs
Request.swift:232
        let queryString = parameters.createPairs(nil).map({ (pair) in
Request.swift:252
        let queryString = parameters.createPairs(nil).map({ (pair) in
Request.swift:271
        for pair in parameters.createPairs(nil) {
Request.swift:340
        for pair in params.createPairs(nil) {
(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:119
                    collect.appendContentsOf(subParam.createPairs(useKey))
Request.swift:145
                    collect.appendContentsOf(subParam.createPairs(useKey))
(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:121
                    collect.appendContentsOf(subParam.createPairs(useKey))
Request.swift:147
                    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
Operation.swift:386
        guard let req = NSMutableURLRequest(urlString: url) else { throw HTTPOptError.InvalidRequest }
?(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:390
        req.verb = method
Request.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 {
: 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
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)
: 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
Operation.swift:34
        try request.appendParameters(parameters)
(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
Request.swift:219
            appendParametersAsQueryString(parameters)
Request.swift:312
            appendParametersAsQueryString(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:223
            appendParametersAsUrlEncoding(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:221
            try appendParametersAsMultiPartFormData(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:276
                mutData.appendData(multiFormHeader(key, fileName: upload.fileName,
Request.swift:280
                let str = "\(multiFormHeader(key, fileName: nil, type: nil, multiCRLF: multiCRLF))\(pair.value)"
(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
Operation.swift:44
         try request.appendParametersAsJSON(parameters)
(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
Request.swift:218
        if isURIParam() {
Request.swift:311
        if isURIParam() {
() -> 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:220
        } else if containsFile(parameters) {
(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