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{ 0053 0054 let headers
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): [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:66 return headers.reduce([String]()) { (currentResults: [String], header: (key: String, value: String)) -> [String] in(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:58 return valueFor("content-disposition", parameterName: "name")?.unquote()RequestFormExtension.swift:62 return valueFor("content-disposition", parameterName: "filename")?.unquote()(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:98 return parseMultiPartFormData(body, boundary: "--\(boundary)")(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:106 while let part = nextMultiPart(&generator, boundary: boundary, isFirst: result.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:114 guard nextMultiPartLine(&generator) == boundary else {RequestFormExtension.swift:118 nextMultiPartLine(&generator)RequestFormExtension.swift:121 while let line = nextMultiPartLine(&generator) where !line.isEmpty {= UInt8(13) 0147 static let NL
RequestFormExtension.swift:136 if value > Request.CR {RequestFormExtension.swift:161 if body.last == Request.CR {= UInt8(10) 0148 0149 private func nextMultiPartBody
RequestFormExtension.swift:139 if value == Request.NL {RequestFormExtension.swift:158 if body.last == Request.NL {(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
RequestFormExtension.swift:127 guard let body = nextMultiPartBody(&generator, boundary: boundary) else {