HttpParser.swift 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  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 ReadBodyFailed(String)
  13. case InvalidStatusLine(String)
  14. }
  15. class HttpParser {
  16. func readHttpRequest(socket: Socket) throws -> HttpRequest {
  17. let statusLine = try socket.readLine()
  18. let statusLineTokens = statusLine.split(" ")
  19. print(statusLineTokens)
  20. if statusLineTokens.count < 3 {
  21. throw HttpParserError.InvalidStatusLine(statusLine)
  22. }
  23. let method = statusLineTokens[0]
  24. let path = statusLineTokens[1]
  25. let urlParams = extractUrlParams(path)
  26. let headers = try readHeaders(socket)
  27. if let contentLength = headers["content-length"], let contentLengthValue = Int(contentLength) {
  28. let body = try readBody(socket, size: contentLengthValue)
  29. return HttpRequest(url: path, urlParams: urlParams, method: method, headers: headers, body: body, capturedUrlGroups: [], address: nil)
  30. }
  31. return HttpRequest(url: path, urlParams: urlParams, method: method, headers: headers, body: nil, capturedUrlGroups: [], address: nil)
  32. }
  33. private func extractUrlParams(url: String) -> [(String, String)] {
  34. guard let query = url.split("?").last else {
  35. return []
  36. }
  37. return query.split("&").map { (param:String) -> (String, String) in
  38. let tokens = param.split("=")
  39. guard tokens.count >= 2 else {
  40. return ("", "")
  41. }
  42. return (tokens[0].removePercentEncoding(), tokens[1].removePercentEncoding())
  43. }
  44. }
  45. private func readBody(socket: Socket, size: Int) throws -> String {
  46. var body = ""
  47. var counter = 0;
  48. while counter < size {
  49. let c = socket.read()
  50. if c < 0 {
  51. throw HttpParserError.ReadBodyFailed(String.fromCString(UnsafePointer(strerror(errno))) ?? "Error: \(errno)")
  52. }
  53. body.append(UnicodeScalar(c))
  54. counter++;
  55. }
  56. return body
  57. }
  58. private func readHeaders(socket: Socket) throws -> [String: String] {
  59. var requestHeaders = [String: String]()
  60. repeat {
  61. let headerLine = try socket.readLine()
  62. if headerLine.isEmpty {
  63. return requestHeaders
  64. }
  65. let headerTokens = headerLine.split(":")
  66. if headerTokens.count >= 2 {
  67. // RFC 2616 - "Hypertext Transfer Protocol -- HTTP/1.1", paragraph 4.2, "Message Headers":
  68. // "Each header field consists of a name followed by a colon (":") and the field value. Field names are case-insensitive."
  69. // We will keep lower case version.
  70. let headerName = headerTokens[0].lowercaseString
  71. let headerValue = headerTokens[1].trim()
  72. if !headerName.isEmpty && !headerValue.isEmpty {
  73. requestHeaders.updateValue(headerValue, forKey: headerName)
  74. }
  75. }
  76. } while true
  77. }
  78. func supportsKeepAlive(headers: [String: String]) -> Bool {
  79. if let value = headers["connection"] {
  80. return "keep-alive" == value.trim()
  81. }
  82. return false
  83. }
  84. }