HttpResponse.swift 5.0 KB

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