0001 import Foundation
0002 import Echo
0003 import Vaquita
0004
0005 #if os(Linux)
0006 import Glibc
0007 #else
0008 import Darwin
0009 #endif
0010
0011 public class Multiparser| Multiparser.swift:233 | if value > Multiparser.CR { |
| Multiparser.swift:236 | if value == Multiparser.NL { |
| Multiparser.swift:264 | if body.last == Multiparser.NL { |
| Multiparser.swift:268 | if body.last == Multiparser.CR { |
: Middleware {
0012
0013 let multipartFormIdentifier = "multipart/form-data"
0014 let boundaryIdentifier = "boundary"
0015
0016 let directory| Multiparser.swift:24 | self.directory = directory |
| Multiparser.swift:29 | self.directory = NSTemporaryDirectory() |
: String
0017
0018 public init(directory: String? = nil) {
0019 #if os(Linux)
0020 srand(UInt32(time(nil)))
0021 #endif
0022
0023 if let directory = directory {
0024 self.directory = directory
0025 } else {
0026 #if os(Linux)
0027 self.directory = "/var/tmp/"
0028 #else
0029 self.directory = NSTemporaryDirectory()
0030 #endif
0031 }
0032 }
0033
0034
0035 func writeData(data: [UInt8], toPath path: String) throws {
0036 let raw = NSData(bytesNoCopy: UnsafeMutablePointer<Void>(data),
0037 length: data.count * sizeof(UInt8), freeWhenDone: false)
0038
0039 try raw.writeToFile(path, options: .DataWritingAtomic)
0040 }
0041
0042 public func handle(request: Request, response: Response, next: (() -> ())) {
0043
0044 guard let contentTypeHeader = request.headers["content-type"] else {
0045 next()
0046 return
0047 }
0048
0049 let contentTypeHeaderTokens = contentTypeHeader.split(";").map { $0.trim() }
0050 guard let contentType = contentTypeHeaderTokens.first where contentType == "multipart/form-data" else {
0051 next()
0052 return
0053 }
0054
0055 var boundary: String? = nil
0056
0057 for token in contentTypeHeaderTokens {
0058
0059 let tokens = token.split("=")
0060
0061 if let key = tokens.first where key == "boundary" && tokens.count == 2 {
0062 boundary = tokens.last
0063 }
0064 }
0065
0066 if let boundary = boundary where boundary.utf8.count > 0 {
0067
0068 dispatch_async(dispatch_get_global_queue(0, 0), {
0069
0070 let multiparts = self.parseMultiPartFormData(request.body, boundary: "--\(boundary)")
0071
0072 for multipart in multiparts {
0073 if let fileName = multipart.fileName,
0074 let ext = fileName.split(".").last,
0075 let fieldName = multipart.name {
0076
0077 let name = self.randomStringWithLengthAndTime(10)
0078 let size = multipart.body.size
0079 let mimetype = MimeType.forExtension(ext)
0080
0081 let path = self.directory + name + "." + ext
0082 do {
0083 try Vaquita.writeDataSync(multipart.body, toFilePath: path)
0084
0085 let file = MultipartFile(name: name, ext: ext, size: size,
0086 mimetype: mimetype, originalName: fileName,
0087 fieldName: fieldName, path: path)
0088
0089 if request.files[fieldName] == nil {
0090
0091 request.files[fieldName] = []
0092 }
0093
0094 request.files[fieldName]!.append(file)
0095 } catch let errorMessage {
0096 print("Boundry Error: \(errorMessage)")
0097 }
0098
0099 } else {
0100 if let value = multipart.value, let name = multipart.name {
0101 request.data[name] = value
0102 }
0103 }
0104 }
0105
0106 next()
0107 })
0108 } else {
0109 next()
0110 }
0111 }
0112
0113 func randomStringWithLengthAndTime(length: Int) -> String {
0114
0115 let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".characters
0116
0117 let randomString: String
0118
0119 let lettersLength = UInt32(letters.count)
0120
0121 let randomCharacters = (0 ..< length).map { i -> String in
0122 #if os(Linux)
0123 let offset = Int(UInt32(rand()) % UInt32(lettersLength))
0124 #else
0125 let offset = Int(arc4random_uniform(lettersLength))
0126 #endif
0127 let c = letters[letters.startIndex.advancedBy(offset)]
0128 return String(c)
0129 }
0130
0131 randomString = randomCharacters.joinWithSeparator("")
0132
0133 let time = "\(NSDate().timeIntervalSinceReferenceDate)"
0134
0135 return "\(randomString)\(time.split(".").joinWithSeparator(""))"
0136 }
0137
0138 struct MultiPart| Multiparser.swift:187 | private func parseMultiPartFormData(data: Data, boundary: String) -> [MultiPart] { |
| Multiparser.swift:191 | var result = [MultiPart]() |
| Multiparser.swift:202 | boundary: String, isFirst: Bool) -> MultiPart? { |
| Multiparser.swift:227 | return MultiPart(headers: headers, body: body) |
{
0139
0140 let headers| Multiparser.swift:169 | return headers.reduce([String]()) { (currentResults: [String], |
: [String: String]
0141
0142 let body: Data
0143
0144 var name: String? {
0145 return valueFor("content-disposition", parameterName: "name")?.unquote()
0146 }
0147
0148 var fileName: String? {
0149 return valueFor("content-disposition", parameterName: "filename")?.unquote()
0150 }
0151
0152 var value: String? {
0153 let string: String?
0154 do {
0155 string = try body.toString()
0156 } catch {
0157 string = nil
0158 }
0159
0160 if string?.characters.count > 0 {
0161 return string
0162 } else {
0163 return nil
0164 }
0165 }
0166
0167 private func valueFor| Multiparser.swift:145 | return valueFor("content-disposition", parameterName: "name")?.unquote() |
| Multiparser.swift:149 | return valueFor("content-disposition", parameterName: "filename")?.unquote() |
(headerName: String, parameterName: String) -> String? {
0168
0169 return headers.reduce([String]()) { (currentResults: [String],
0170 header: (key: String, value: String)) -> [String] in
0171
0172 guard header.key == headerName else {
0173 return currentResults
0174 }
0175 let headerValueParams = header.value.split(";").map { $0.trim() }
0176 return headerValueParams.reduce(currentResults, combine: { (results:[String], token: String) -> [String] in
0177 let parameterTokens = token.split(1, separator: "=")
0178 if parameterTokens.first == parameterName, let value = parameterTokens.last {
0179 return results + [value]
0180 }
0181 return results
0182 })
0183 }.first
0184 }
0185 }
0186
0187 private func parseMultiPartFormData(data: Data, boundary: String) -> [MultiPart] {
0188
0189 var generator = data.bytes.generate()
0190
0191 var result = [MultiPart]()
0192
0193 while let part = nextMultiPart(&generator, boundary: boundary, isFirst: result.isEmpty) {
0194
0195 result.append(part)
0196
0197 }
0198 return result
0199 }
0200
0201 private func nextMultiPart(inout generator: IndexingGenerator<[UInt8]>,
0202 boundary: String, isFirst: Bool) -> MultiPart? {
0203 if isFirst {
0204 guard nextMultiPartLine(&generator) == boundary else {
0205 return nil
0206 }
0207 } else {
0208 nextMultiPartLine(&generator)
0209 }
0210
0211 var headers = [String: String]()
0212
0213 while let line = nextMultiPartLine(&generator) where !line.isEmpty {
0214
0215 let tokens = line.split(":")
0216
0217 if let name = tokens.first, value = tokens.last where tokens.count == 2 {
0218 headers[name.lowercaseString] = value.trim()
0219 }
0220
0221 }
0222
0223 guard let body = nextMultiPartBody(&generator, boundary: boundary) else {
0224 return nil
0225 }
0226
0227 return MultiPart(headers: headers, body: body)
0228 }
0229
0230 private func nextMultiPartLine| Multiparser.swift:204 | guard nextMultiPartLine(&generator) == boundary else { |
| Multiparser.swift:208 | nextMultiPartLine(&generator) |
| Multiparser.swift:213 | while let line = nextMultiPartLine(&generator) where !line.isEmpty { |
(inout generator: IndexingGenerator<[UInt8]>) -> String? {
0231 var result = String()
0232 while let value = generator.next() {
0233 if value > Multiparser.CR {
0234 result.append(Character(UnicodeScalar(value)))
0235 }
0236 if value == Multiparser.NL {
0237 break
0238 }
0239 }
0240 return result
0241 }
0242
0243 static let CR| Multiparser.swift:233 | if value > Multiparser.CR { |
| Multiparser.swift:268 | if body.last == Multiparser.CR { |
= UInt8(13)
0244 static let NL| Multiparser.swift:236 | if value == Multiparser.NL { |
| Multiparser.swift:264 | if body.last == Multiparser.NL { |
= UInt8(10)
0245
0246 private func nextMultiPartBody(inout generator: IndexingGenerator<[UInt8]>, boundary: String) -> Data? {
0247
0248 var body = [UInt8]()
0249
0250 let boundaryArray = [UInt8](boundary.utf8)
0251
0252 var matchOffset = 0;
0253
0254 while let x = generator.next() {
0255
0256 matchOffset = ( x == boundaryArray[matchOffset] ? matchOffset + 1 : 0 )
0257
0258 body.append(x)
0259
0260 if matchOffset == boundaryArray.count {
0261
0262 body.removeRange(Range<Int>(body.count - matchOffset ..< body.count))
0263
0264 if body.last == Multiparser.NL {
0265
0266 body.removeLast()
0267
0268 if body.last == Multiparser.CR {
0269 body.removeLast()
0270 }
0271 }
0272
0273 return Data(bytes: body)
0274 }
0275 }
0276 return nil
0277 }
0278
0279 }
0280