HttpParser.swift 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. //
  2. // HttpParser.swift
  3. // Swifter
  4. // Copyright (c) 2015 Damian Kołakowski. All rights reserved.
  5. //
  6. #if os(Linux)
  7. import Glibc
  8. #else
  9. import Foundation
  10. #endif
  11. enum HttpParserError: ErrorType {
  12. case InvalidStatusLine(String)
  13. }
  14. class HttpParser {
  15. func readHttpRequest(socket: Socket) throws -> HttpRequest {
  16. let statusLine = try socket.readLine()
  17. let statusLineTokens = statusLine.split(" ")
  18. if statusLineTokens.count < 3 {
  19. throw HttpParserError.InvalidStatusLine(statusLine)
  20. }
  21. let request = HttpRequest()
  22. request.method = statusLineTokens[0]
  23. request.path = statusLineTokens[1]
  24. request.queryParams = extractQueryParams(request.path)
  25. request.headers = try readHeaders(socket)
  26. if let contentLength = request.headers["content-length"], let contentLengthValue = Int(contentLength) {
  27. request.body = try readBody(socket, size: contentLengthValue)
  28. }
  29. return request
  30. }
  31. private func extractQueryParams(url: String) -> [(String, String)] {
  32. guard let query = url.split("?").last else {
  33. return []
  34. }
  35. return query.split("&").reduce([(String, String)]()) { (c, s) -> [(String, String)] in
  36. let tokens = s.split(1, separator: "=")
  37. if let name = tokens.first, value = tokens.last {
  38. return c + [(name.removePercentEncoding(), value.removePercentEncoding())]
  39. }
  40. return c
  41. }
  42. }
  43. private func readBody(socket: Socket, size: Int) throws -> [UInt8] {
  44. var body = [UInt8]()
  45. var counter = 0
  46. while counter < size {
  47. body.append(try socket.read())
  48. counter++
  49. }
  50. return body
  51. }
  52. private func readHeaders(socket: Socket) throws -> [String: String] {
  53. var requestHeaders = [String: String]()
  54. repeat {
  55. let headerLine = try socket.readLine()
  56. if headerLine.isEmpty {
  57. return requestHeaders
  58. }
  59. let headerTokens = headerLine.split(1, separator: ":")
  60. if let name = headerTokens.first, value = headerTokens.last {
  61. requestHeaders[name.lowercaseString] = value.trim()
  62. }
  63. } while true
  64. }
  65. func supportsKeepAlive(headers: [String: String]) -> Bool {
  66. if let value = headers["connection"] {
  67. return "keep-alive" == value.trim()
  68. }
  69. return false
  70. }
  71. }