// // HttpParser.swift // Swifter // Copyright (c) 2015 Damian KoĊ‚akowski. All rights reserved. // #if os(Linux) import Glibc #else import Foundation #endif enum HttpParserError: ErrorType { case InvalidStatusLine(String) } class HttpParser { func readHttpRequest(socket: Socket) throws -> HttpRequest { let statusLine = try socket.readLine() let statusLineTokens = statusLine.split(" ") print(statusLineTokens) if statusLineTokens.count < 3 { throw HttpParserError.InvalidStatusLine(statusLine) } var request = HttpRequest() request.method = statusLineTokens[0] request.url = statusLineTokens[1] request.queryParams = extractQueryParams(request.url) request.headers = try readHeaders(socket) if let contentLength = request.headers["content-length"], let contentLengthValue = Int(contentLength) { request.body = try readBody(socket, size: contentLengthValue) } return request } private func extractQueryParams(url: String) -> [(String, String)] { guard let query = url.split("?").last else { return [] } return query.split("&").map { (param: String) -> (String, String) in let tokens = param.split("=") guard let name = tokens.first else { return ("", "") } guard let value = tokens.last where tokens.count > 1 else { return (name.removePercentEncoding(), "") } return (name.removePercentEncoding(), value.removePercentEncoding()) } } private func readBody(socket: Socket, size: Int) throws -> [UInt8] { var body = [UInt8]() var counter = 0 while counter < size { body.append(try socket.read()) counter++ } return body } private func readHeaders(socket: Socket) throws -> [String: String] { var requestHeaders = [String: String]() repeat { let headerLine = try socket.readLine() if headerLine.isEmpty { return requestHeaders } let headerTokens = headerLine.split(":") if let name = headerTokens.first where headerTokens.count >= 2 { let value = headerTokens.dropFirst().joinWithSeparator(":") requestHeaders[name.lowercaseString] = value.trim() } } while true } func supportsKeepAlive(headers: [String: String]) -> Bool { if let value = headers["connection"] { return "keep-alive" == value.trim() } return false } }