HttpResponse.swift 4.3 KB

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