HttpResponse.swift 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. //
  2. // HttpResponse.swift
  3. // Swifter
  4. // Copyright (c) 2015 Damian Kołakowski. All rights reserved.
  5. //
  6. import Foundation
  7. public enum SerializationError: ErrorType {
  8. case InvalidObject
  9. case NotSupported
  10. }
  11. public protocol HttpResponseBodyWriter {
  12. func write(data: [UInt8])
  13. }
  14. public enum HttpResponseBody {
  15. case Json(AnyObject)
  16. case Html(String)
  17. case Text(String)
  18. case Custom(Any, (Any) throws -> String)
  19. func content() -> (Int, ((HttpResponseBodyWriter) throws -> Void)?) {
  20. do {
  21. switch self {
  22. case .Json(let object):
  23. guard NSJSONSerialization.isValidJSONObject(object) else {
  24. throw SerializationError.InvalidObject
  25. }
  26. let json = try NSJSONSerialization.dataWithJSONObject(object, options: NSJSONWritingOptions.PrettyPrinted)
  27. let data = Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>(json.bytes), count: json.length))
  28. return (data.count, {
  29. $0.write(data)
  30. })
  31. case .Text(let body):
  32. let data = [UInt8](body.utf8)
  33. return (data.count, {
  34. $0.write(data)
  35. })
  36. case .Html(let body):
  37. let serialised = "<html><meta charset=\"UTF-8\"><body>\(body)</body></html>"
  38. let data = [UInt8](serialised.utf8)
  39. return (data.count, {
  40. $0.write(data)
  41. })
  42. case .Custom(let object, let closure):
  43. let serialised = try closure(object)
  44. let data = [UInt8](serialised.utf8)
  45. return (data.count, {
  46. $0.write(data)
  47. })
  48. }
  49. } catch {
  50. let data = [UInt8]("Serialisation error: \(error)".utf8)
  51. return (data.count, {
  52. $0.write(data)
  53. })
  54. }
  55. }
  56. }
  57. public enum HttpResponse {
  58. case OK(HttpResponseBody), Created, Accepted
  59. case MovedPermanently(String)
  60. case BadRequest, Unauthorized, Forbidden, NotFound
  61. case InternalServerError
  62. case RAW(Int, String, [String:String]?, ((HttpResponseBodyWriter) -> Void)? )
  63. func statusCode() -> Int {
  64. switch self {
  65. case .OK(_) : return 200
  66. case .Created : return 201
  67. case .Accepted : return 202
  68. case .MovedPermanently : return 301
  69. case .BadRequest : return 400
  70. case .Unauthorized : return 401
  71. case .Forbidden : return 403
  72. case .NotFound : return 404
  73. case .InternalServerError : return 500
  74. case .RAW(let code, _ , _, _) : return code
  75. }
  76. }
  77. func reasonPhrase() -> String {
  78. switch self {
  79. case .OK(_) : return "OK"
  80. case .Created : return "Created"
  81. case .Accepted : return "Accepted"
  82. case .MovedPermanently : return "Moved Permanently"
  83. case .BadRequest : return "Bad Request"
  84. case .Unauthorized : return "Unauthorized"
  85. case .Forbidden : return "Forbidden"
  86. case .NotFound : return "Not Found"
  87. case .InternalServerError : return "Internal Server Error"
  88. case .RAW(_, let phrase, _, _) : return phrase
  89. }
  90. }
  91. func headers() -> [String: String] {
  92. var headers = ["Server" : "Swifter \(HttpServer.VERSION)"]
  93. switch self {
  94. case .OK(let body):
  95. switch body {
  96. case .Json(_) : headers["Content-Type"] = "application/json"
  97. case .Html(_) : headers["Content-Type"] = "text/html"
  98. default:break
  99. }
  100. case .MovedPermanently(let location):
  101. headers["Location"] = location
  102. case .RAW(_, _, let rawHeaders, _):
  103. if let rawHeaders = rawHeaders {
  104. for (k, v) in rawHeaders {
  105. headers.updateValue(v, forKey: k)
  106. }
  107. }
  108. default:break
  109. }
  110. return headers
  111. }
  112. func content() -> (length: Int, writeClosure: ((HttpResponseBodyWriter) throws -> Void)?) {
  113. switch self {
  114. case .OK(let body) : return body.content()
  115. case .RAW(_, _, _, let writer) : return (-1, writer)
  116. default : return (-1, nil)
  117. }
  118. }
  119. }
  120. /**
  121. Makes it possible to compare handler responses with '==', but
  122. ignores any associated values. This should generally be what
  123. you want. E.g.:
  124. let resp = handler(updatedRequest)
  125. if resp == .NotFound {
  126. print("Client requested not found: \(request.url)")
  127. }
  128. */
  129. func ==(inLeft: HttpResponse, inRight: HttpResponse) -> Bool {
  130. return inLeft.statusCode() == inRight.statusCode()
  131. }