HttpParser.swift 3.4 KB

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