0001    /**
0002     Copyright (c) 2014, Damian KoĊ‚akowski
0003     All rights reserved.
0004     
0005     Redistribution and use in source and binary forms, with or without
0006     modification, are permitted provided that the following conditions are met:
0007     
0008     * Redistributions of source code must retain the above copyright notice, this
0009     list of conditions and the following disclaimer.
0010     
0011     * Redistributions in binary form must reproduce the above copyright notice,
0012     this list of conditions and the following disclaimer in the documentation
0013     and/or other materials provided with the distribution.
0014     
0015     * Neither the name of the {organization} nor the names of its
0016     contributors may be used to endorse or promote products derived from
0017     this software without specific prior written permission.
0018     
0019     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0020     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0021     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0022     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
0023     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0024     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
0025     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
0026     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0027     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0028     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029     */
0030    
0031    import Foundation
0032    
0033    extension Request {
0034        func parseUrlencodedForm() -> [(String, String)] {
0035            guard let contentTypeHeader = headers["content-type"] else {
0036                return []
0037            }
0038            let contentTypeHeaderTokens = contentTypeHeader.split(";").map { $0.trim() }
0039            guard let contentType = contentTypeHeaderTokens.first where contentType == "application/x-www-form-urlencoded" else {
0040                return []
0041            }
0042            return String.fromUInt8(body).split("&").map { (param: String) -> (String, String) in
0043                let tokens = param.split("=")
0044                if let name = tokens.first, value = tokens.last where tokens.count == 2 {
0045                    return (name.replace("+", new: " ").removePercentEncoding(),
0046                        value.replace("+", new: " ").removePercentEncoding())
0047                }
0048                return ("","")
0049            }
0050        }
0051        
0052        struct MultiPart
RequestFormExtension.swift:82
    func parseMultiPartFormData() -> [MultiPart] {
RequestFormExtension.swift:103
    private func parseMultiPartFormData(data: [UInt8], boundary: String) -> [MultiPart] {
RequestFormExtension.swift:105
        var result = [MultiPart]()
RequestFormExtension.swift:112
    private func nextMultiPart(inout generator: IndexingGenerator<[UInt8]>, boundary: String, isFirst: Bool) -> MultiPart? {
RequestFormExtension.swift:130
        return MultiPart(headers: headers, body: body)
{ 0053 0054 let headers
RequestFormExtension.swift:66
            return headers.reduce([String]()) { (currentResults: [String], header: (key: String, value: String)) -> [String] in
: [String: String] 0055 let body: [UInt8] 0056 0057 var name: String? { 0058 return valueFor("content-disposition", parameterName: "name")?.unquote() 0059 } 0060 0061 var fileName: String? { 0062 return valueFor("content-disposition", parameterName: "filename")?.unquote() 0063 } 0064 0065 private func valueFor
RequestFormExtension.swift:58
            return valueFor("content-disposition", parameterName: "name")?.unquote()
RequestFormExtension.swift:62
            return valueFor("content-disposition", parameterName: "filename")?.unquote()
(headerName: String, parameterName: String) -> String? { 0066 return headers.reduce([String]()) { (currentResults: [String], header: (key: String, value: String)) -> [String] in 0067 guard header.key == headerName else { 0068 return currentResults 0069 } 0070 let headerValueParams = header.value.split(";").map { $0.trim() } 0071 return headerValueParams.reduce(currentResults, combine: { (results:[String], token: String) -> [String] in 0072 let parameterTokens = token.split(1, separator: "=") 0073 if parameterTokens.first == parameterName, let value = parameterTokens.last { 0074 return results + [value] 0075 } 0076 return results 0077 }) 0078 }.first 0079 } 0080 } 0081 0082 func parseMultiPartFormData() -> [MultiPart] { 0083 guard let contentTypeHeader = headers["content-type"] else { 0084 return [] 0085 } 0086 let contentTypeHeaderTokens = contentTypeHeader.split(";").map { $0.trim() } 0087 guard let contentType = contentTypeHeaderTokens.first where contentType == "multipart/form-data" else { 0088 return [] 0089 } 0090 var boundary: String? = nil 0091 contentTypeHeaderTokens.forEach({ 0092 let tokens = $0.split("=") 0093 if let key = tokens.first where key == "boundary" && tokens.count == 2 { 0094 boundary = tokens.last 0095 } 0096 }) 0097 if let boundary = boundary where boundary.utf8.count > 0 { 0098 return parseMultiPartFormData(body, boundary: "--\(boundary)") 0099 } 0100 return [] 0101 } 0102 0103 private func parseMultiPartFormData
RequestFormExtension.swift:98
            return parseMultiPartFormData(body, boundary: "--\(boundary)")
(data: [UInt8], boundary: String) -> [MultiPart] { 0104 var generator = data.generate() 0105 var result = [MultiPart]() 0106 while let part = nextMultiPart(&generator, boundary: boundary, isFirst: result.isEmpty) { 0107 result.append(part) 0108 } 0109 return result 0110 } 0111 0112 private func nextMultiPart
RequestFormExtension.swift:106
        while let part = nextMultiPart(&generator, boundary: boundary, isFirst: result.isEmpty) {
(inout generator: IndexingGenerator<[UInt8]>, boundary: String, isFirst: Bool) -> MultiPart? { 0113 if isFirst { 0114 guard nextMultiPartLine(&generator) == boundary else { 0115 return nil 0116 } 0117 } else { 0118 nextMultiPartLine(&generator) 0119 } 0120 var headers = [String: String]() 0121 while let line = nextMultiPartLine(&generator) where !line.isEmpty { 0122 let tokens = line.split(":") 0123 if let name = tokens.first, value = tokens.last where tokens.count == 2 { 0124 headers[name.lowercaseString] = value.trim() 0125 } 0126 } 0127 guard let body = nextMultiPartBody(&generator, boundary: boundary) else { 0128 return nil 0129 } 0130 return MultiPart(headers: headers, body: body) 0131 } 0132 0133 private func nextMultiPartLine
RequestFormExtension.swift:114
            guard nextMultiPartLine(&generator) == boundary else {
RequestFormExtension.swift:118
            nextMultiPartLine(&generator)
RequestFormExtension.swift:121
        while let line = nextMultiPartLine(&generator) where !line.isEmpty {
(inout generator: IndexingGenerator<[UInt8]>) -> String? { 0134 var result = String() 0135 while let value = generator.next() { 0136 if value > Request.CR { 0137 result.append(Character(UnicodeScalar(value))) 0138 } 0139 if value == Request.NL { 0140 break 0141 } 0142 } 0143 return result 0144 } 0145 0146 static let CR
RequestFormExtension.swift:136
            if value > Request.CR {
RequestFormExtension.swift:161
                if body.last == Request.CR {
= UInt8(13) 0147 static let NL
RequestFormExtension.swift:139
            if value == Request.NL {
RequestFormExtension.swift:158
                if body.last == Request.NL {
= UInt8(10) 0148 0149 private func nextMultiPartBody
RequestFormExtension.swift:127
        guard let body = nextMultiPartBody(&generator, boundary: boundary) else {
(inout generator: IndexingGenerator<[UInt8]>, boundary: String) -> [UInt8]? { 0150 var body = [UInt8]() 0151 let boundaryArray = [UInt8](boundary.utf8) 0152 var matchOffset = 0; 0153 while let x = generator.next() { 0154 matchOffset = ( x == boundaryArray[matchOffset] ? matchOffset + 1 : 0 ) 0155 body.append(x) 0156 if matchOffset == boundaryArray.count { 0157 body.removeRange(Range(body.count-matchOffset..<body.count)) 0158 if body.last == Request.NL { 0159 body.removeLast() 0160 } 0161 if body.last == Request.CR { 0162 body.removeLast() 0163 } 0164 return body 0165 } 0166 } 0167 return nil 0168 } 0169 } 0170