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. }
  11. public enum HttpResponseBody {
  12. case Json(AnyObject)
  13. case Html(String)
  14. case Text(String)
  15. case Custom(Any, (Any) throws -> String)
  16. func data() -> [UInt8]? {
  17. do {
  18. switch self {
  19. case .Json(let object):
  20. guard case let obj = object where NSJSONSerialization.isValidJSONObject(obj) else {
  21. throw SerializationError.InvalidObject
  22. }
  23. let json = try NSJSONSerialization.dataWithJSONObject(obj, options: NSJSONWritingOptions.PrettyPrinted)
  24. return Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>(json.bytes), count: json.length))
  25. case .Text(let body):
  26. let serialised = body
  27. return [UInt8](serialised.utf8)
  28. case .Html(let body):
  29. let serialised = "<html><meta charset=\"UTF-8\"><body>\(body)</body></html>"
  30. return [UInt8](serialised.utf8)
  31. case .Custom(let object, let closure):
  32. let serialised = try closure(object)
  33. return [UInt8](serialised.utf8)
  34. }
  35. } catch {
  36. return [UInt8]("Serialisation error: \(error)".utf8)
  37. }
  38. }
  39. }
  40. public enum HttpResponse {
  41. case OK(HttpResponseBody), Created, Accepted
  42. case MovedPermanently(String)
  43. case BadRequest, Unauthorized, Forbidden, NotFound
  44. case InternalServerError
  45. case RAW(Int, String, [String:String]?, [UInt8]?)
  46. func statusCode() -> Int {
  47. switch self {
  48. case .OK(_) : return 200
  49. case .Created : return 201
  50. case .Accepted : return 202
  51. case .MovedPermanently : return 301
  52. case .BadRequest : return 400
  53. case .Unauthorized : return 401
  54. case .Forbidden : return 403
  55. case .NotFound : return 404
  56. case .InternalServerError : return 500
  57. case .RAW(let code, _ , _, _) : return code
  58. }
  59. }
  60. func reasonPhrase() -> String {
  61. switch self {
  62. case .OK(_) : return "OK"
  63. case .Created : return "Created"
  64. case .Accepted : return "Accepted"
  65. case .MovedPermanently : return "Moved Permanently"
  66. case .BadRequest : return "Bad Request"
  67. case .Unauthorized : return "Unauthorized"
  68. case .Forbidden : return "Forbidden"
  69. case .NotFound : return "Not Found"
  70. case .InternalServerError : return "Internal Server Error"
  71. case .RAW(_, let phrase, _, _) : return phrase
  72. }
  73. }
  74. func headers() -> [String: String] {
  75. var headers = ["Server" : "Swifter \(Constants.VERSION)"]
  76. switch self {
  77. case .OK(let body):
  78. switch body {
  79. case .Json(_) : headers["Content-Type"] = "application/json"
  80. case .Html(_) : headers["Content-Type"] = "text/html"
  81. default:break
  82. }
  83. case .MovedPermanently(let location):
  84. 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. }