HttpParser.swift 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  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("&").map { (param: String) -> (String, String) in
  36. let tokens = param.split("=")
  37. guard let name = tokens.first else {
  38. return ("", "")
  39. }
  40. guard let value = tokens.last where tokens.count > 1 else {
  41. return (name.removePercentEncoding(), "")
  42. }
  43. return (name.removePercentEncoding(), value.removePercentEncoding())
  44. }
  45. }
  46. private func readBody(socket: Socket, size: Int) throws -> [UInt8] {
  47. var body = [UInt8]()
  48. var counter = 0
  49. while counter < size {
  50. body.append(try socket.read())
  51. counter++
  52. }
  53. return body
  54. }
  55. private func readHeaders(socket: Socket) throws -> [String: String] {
  56. var requestHeaders = [String: String]()
  57. repeat {
  58. let headerLine = try socket.readLine()
  59. if headerLine.isEmpty {
  60. return requestHeaders
  61. }
  62. let headerTokens = headerLine.split(":")
  63. if let name = headerTokens.first where headerTokens.count >= 2 {
  64. let value = headerTokens.dropFirst().joinWithSeparator(":")
  65. requestHeaders[name.lowercaseString] = value.trim()
  66. }
  67. } while true
  68. }
  69. func supportsKeepAlive(headers: [String: String]) -> Bool {
  70. if let value = headers["connection"] {
  71. return "keep-alive" == value.trim()
  72. }
  73. return false
  74. }
  75. }