HTTPResponseStatus.swift 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /// A HTTP response status code.
  2. public enum HTTPResponseStatus {
  3. /* use custom if you want to use a non-standard response code or
  4. have it available in a (UInt, String) pair from a higher-level web framework. */
  5. case custom(code: UInt, reasonPhrase: String)
  6. /* all the codes from http://www.iana.org/assignments/http-status-codes */
  7. // 1xx
  8. case `continue`
  9. case switchingProtocols
  10. case processing
  11. // TODO: add '103: Early Hints' (requires bumping SemVer major).
  12. // 2xx
  13. case ok
  14. case created
  15. case accepted
  16. case nonAuthoritativeInformation
  17. case noContent
  18. case resetContent
  19. case partialContent
  20. case multiStatus
  21. case alreadyReported
  22. case imUsed
  23. // 3xx
  24. case multipleChoices
  25. case movedPermanently
  26. case found
  27. case seeOther
  28. case notModified
  29. case useProxy
  30. case temporaryRedirect
  31. case permanentRedirect
  32. // 4xx
  33. case badRequest
  34. case unauthorized
  35. case paymentRequired
  36. case forbidden
  37. case notFound
  38. case methodNotAllowed
  39. case notAcceptable
  40. case proxyAuthenticationRequired
  41. case requestTimeout
  42. case conflict
  43. case gone
  44. case lengthRequired
  45. case preconditionFailed
  46. case payloadTooLarge
  47. case uriTooLong
  48. case unsupportedMediaType
  49. case rangeNotSatisfiable
  50. case expectationFailed
  51. case imATeapot
  52. case misdirectedRequest
  53. case unprocessableEntity
  54. case locked
  55. case failedDependency
  56. case upgradeRequired
  57. case preconditionRequired
  58. case tooManyRequests
  59. case requestHeaderFieldsTooLarge
  60. case unavailableForLegalReasons
  61. // 5xx
  62. case internalServerError
  63. case notImplemented
  64. case badGateway
  65. case serviceUnavailable
  66. case gatewayTimeout
  67. case httpVersionNotSupported
  68. case variantAlsoNegotiates
  69. case insufficientStorage
  70. case loopDetected
  71. case notExtended
  72. case networkAuthenticationRequired
  73. /// Whether responses with this status code may have a response body.
  74. public var mayHaveResponseBody: Bool {
  75. switch self {
  76. case .continue,
  77. .switchingProtocols,
  78. .processing,
  79. .noContent,
  80. .custom where (code < 200) && (code >= 100):
  81. return false
  82. default:
  83. return true
  84. }
  85. }
  86. /// Initialize a `HTTPResponseStatus` from a given status and reason.
  87. ///
  88. /// - Parameter statusCode: The integer value of the HTTP response status code
  89. /// - Parameter reasonPhrase: The textual reason phrase from the response. This will be
  90. /// discarded in favor of the default if the `statusCode` matches one that we know.
  91. public init(statusCode: Int, reasonPhrase: String = "") {
  92. switch statusCode {
  93. case 100:
  94. self = .continue
  95. case 101:
  96. self = .switchingProtocols
  97. case 102:
  98. self = .processing
  99. case 200:
  100. self = .ok
  101. case 201:
  102. self = .created
  103. case 202:
  104. self = .accepted
  105. case 203:
  106. self = .nonAuthoritativeInformation
  107. case 204:
  108. self = .noContent
  109. case 205:
  110. self = .resetContent
  111. case 206:
  112. self = .partialContent
  113. case 207:
  114. self = .multiStatus
  115. case 208:
  116. self = .alreadyReported
  117. case 226:
  118. self = .imUsed
  119. case 300:
  120. self = .multipleChoices
  121. case 301:
  122. self = .movedPermanently
  123. case 302:
  124. self = .found
  125. case 303:
  126. self = .seeOther
  127. case 304:
  128. self = .notModified
  129. case 305:
  130. self = .useProxy
  131. case 307:
  132. self = .temporaryRedirect
  133. case 308:
  134. self = .permanentRedirect
  135. case 400:
  136. self = .badRequest
  137. case 401:
  138. self = .unauthorized
  139. case 402:
  140. self = .paymentRequired
  141. case 403:
  142. self = .forbidden
  143. case 404:
  144. self = .notFound
  145. case 405:
  146. self = .methodNotAllowed
  147. case 406:
  148. self = .notAcceptable
  149. case 407:
  150. self = .proxyAuthenticationRequired
  151. case 408:
  152. self = .requestTimeout
  153. case 409:
  154. self = .conflict
  155. case 410:
  156. self = .gone
  157. case 411:
  158. self = .lengthRequired
  159. case 412:
  160. self = .preconditionFailed
  161. case 413:
  162. self = .payloadTooLarge
  163. case 414:
  164. self = .uriTooLong
  165. case 415:
  166. self = .unsupportedMediaType
  167. case 416:
  168. self = .rangeNotSatisfiable
  169. case 417:
  170. self = .expectationFailed
  171. case 418:
  172. self = .imATeapot
  173. case 421:
  174. self = .misdirectedRequest
  175. case 422:
  176. self = .unprocessableEntity
  177. case 423:
  178. self = .locked
  179. case 424:
  180. self = .failedDependency
  181. case 426:
  182. self = .upgradeRequired
  183. case 428:
  184. self = .preconditionRequired
  185. case 429:
  186. self = .tooManyRequests
  187. case 431:
  188. self = .requestHeaderFieldsTooLarge
  189. case 451:
  190. self = .unavailableForLegalReasons
  191. case 500:
  192. self = .internalServerError
  193. case 501:
  194. self = .notImplemented
  195. case 502:
  196. self = .badGateway
  197. case 503:
  198. self = .serviceUnavailable
  199. case 504:
  200. self = .gatewayTimeout
  201. case 505:
  202. self = .httpVersionNotSupported
  203. case 506:
  204. self = .variantAlsoNegotiates
  205. case 507:
  206. self = .insufficientStorage
  207. case 508:
  208. self = .loopDetected
  209. case 510:
  210. self = .notExtended
  211. case 511:
  212. self = .networkAuthenticationRequired
  213. default:
  214. self = .custom(code: UInt(statusCode), reasonPhrase: reasonPhrase)
  215. }
  216. }
  217. }
  218. extension HTTPResponseStatus: Equatable {
  219. public static func == (lhs: HTTPResponseStatus, rhs: HTTPResponseStatus) -> Bool {
  220. switch (lhs, rhs) {
  221. case let (.custom(lcode, lreason), .custom(rcode, rreason)):
  222. return lcode == rcode && lreason == rreason
  223. case (.custom, _), (_, .custom):
  224. return false
  225. default:
  226. return lhs.code == rhs.code
  227. }
  228. }
  229. }
  230. extension HTTPResponseStatus {
  231. /// The numerical status code for a given HTTP response status.
  232. public var code: UInt {
  233. switch self {
  234. case .continue:
  235. return 100
  236. case .switchingProtocols:
  237. return 101
  238. case .processing:
  239. return 102
  240. case .ok:
  241. return 200
  242. case .created:
  243. return 201
  244. case .accepted:
  245. return 202
  246. case .nonAuthoritativeInformation:
  247. return 203
  248. case .noContent:
  249. return 204
  250. case .resetContent:
  251. return 205
  252. case .partialContent:
  253. return 206
  254. case .multiStatus:
  255. return 207
  256. case .alreadyReported:
  257. return 208
  258. case .imUsed:
  259. return 226
  260. case .multipleChoices:
  261. return 300
  262. case .movedPermanently:
  263. return 301
  264. case .found:
  265. return 302
  266. case .seeOther:
  267. return 303
  268. case .notModified:
  269. return 304
  270. case .useProxy:
  271. return 305
  272. case .temporaryRedirect:
  273. return 307
  274. case .permanentRedirect:
  275. return 308
  276. case .badRequest:
  277. return 400
  278. case .unauthorized:
  279. return 401
  280. case .paymentRequired:
  281. return 402
  282. case .forbidden:
  283. return 403
  284. case .notFound:
  285. return 404
  286. case .methodNotAllowed:
  287. return 405
  288. case .notAcceptable:
  289. return 406
  290. case .proxyAuthenticationRequired:
  291. return 407
  292. case .requestTimeout:
  293. return 408
  294. case .conflict:
  295. return 409
  296. case .gone:
  297. return 410
  298. case .lengthRequired:
  299. return 411
  300. case .preconditionFailed:
  301. return 412
  302. case .payloadTooLarge:
  303. return 413
  304. case .uriTooLong:
  305. return 414
  306. case .unsupportedMediaType:
  307. return 415
  308. case .rangeNotSatisfiable:
  309. return 416
  310. case .expectationFailed:
  311. return 417
  312. case .imATeapot:
  313. return 418
  314. case .misdirectedRequest:
  315. return 421
  316. case .unprocessableEntity:
  317. return 422
  318. case .locked:
  319. return 423
  320. case .failedDependency:
  321. return 424
  322. case .upgradeRequired:
  323. return 426
  324. case .preconditionRequired:
  325. return 428
  326. case .tooManyRequests:
  327. return 429
  328. case .requestHeaderFieldsTooLarge:
  329. return 431
  330. case .unavailableForLegalReasons:
  331. return 451
  332. case .internalServerError:
  333. return 500
  334. case .notImplemented:
  335. return 501
  336. case .badGateway:
  337. return 502
  338. case .serviceUnavailable:
  339. return 503
  340. case .gatewayTimeout:
  341. return 504
  342. case .httpVersionNotSupported:
  343. return 505
  344. case .variantAlsoNegotiates:
  345. return 506
  346. case .insufficientStorage:
  347. return 507
  348. case .loopDetected:
  349. return 508
  350. case .notExtended:
  351. return 510
  352. case .networkAuthenticationRequired:
  353. return 511
  354. case .custom(code: let code, reasonPhrase: _):
  355. return code
  356. }
  357. }
  358. /// The string reason phrase for a given HTTP response status.
  359. public var reasonPhrase: String {
  360. switch self {
  361. case .continue:
  362. return "Continue"
  363. case .switchingProtocols:
  364. return "Switching Protocols"
  365. case .processing:
  366. return "Processing"
  367. case .ok:
  368. return "OK"
  369. case .created:
  370. return "Created"
  371. case .accepted:
  372. return "Accepted"
  373. case .nonAuthoritativeInformation:
  374. return "Non-Authoritative Information"
  375. case .noContent:
  376. return "No Content"
  377. case .resetContent:
  378. return "Reset Content"
  379. case .partialContent:
  380. return "Partial Content"
  381. case .multiStatus:
  382. return "Multi-Status"
  383. case .alreadyReported:
  384. return "Already Reported"
  385. case .imUsed:
  386. return "IM Used"
  387. case .multipleChoices:
  388. return "Multiple Choices"
  389. case .movedPermanently:
  390. return "Moved Permanently"
  391. case .found:
  392. return "Found"
  393. case .seeOther:
  394. return "See Other"
  395. case .notModified:
  396. return "Not Modified"
  397. case .useProxy:
  398. return "Use Proxy"
  399. case .temporaryRedirect:
  400. return "Temporary Redirect"
  401. case .permanentRedirect:
  402. return "Permanent Redirect"
  403. case .badRequest:
  404. return "Bad Request"
  405. case .unauthorized:
  406. return "Unauthorized"
  407. case .paymentRequired:
  408. return "Payment Required"
  409. case .forbidden:
  410. return "Forbidden"
  411. case .notFound:
  412. return "Not Found"
  413. case .methodNotAllowed:
  414. return "Method Not Allowed"
  415. case .notAcceptable:
  416. return "Not Acceptable"
  417. case .proxyAuthenticationRequired:
  418. return "Proxy Authentication Required"
  419. case .requestTimeout:
  420. return "Request Timeout"
  421. case .conflict:
  422. return "Conflict"
  423. case .gone:
  424. return "Gone"
  425. case .lengthRequired:
  426. return "Length Required"
  427. case .preconditionFailed:
  428. return "Precondition Failed"
  429. case .payloadTooLarge:
  430. return "Payload Too Large"
  431. case .uriTooLong:
  432. return "URI Too Long"
  433. case .unsupportedMediaType:
  434. return "Unsupported Media Type"
  435. case .rangeNotSatisfiable:
  436. return "Range Not Satisfiable"
  437. case .expectationFailed:
  438. return "Expectation Failed"
  439. case .imATeapot:
  440. return "I'm a teapot"
  441. case .misdirectedRequest:
  442. return "Misdirected Request"
  443. case .unprocessableEntity:
  444. return "Unprocessable Entity"
  445. case .locked:
  446. return "Locked"
  447. case .failedDependency:
  448. return "Failed Dependency"
  449. case .upgradeRequired:
  450. return "Upgrade Required"
  451. case .preconditionRequired:
  452. return "Precondition Required"
  453. case .tooManyRequests:
  454. return "Too Many Requests"
  455. case .requestHeaderFieldsTooLarge:
  456. return "Request Header Fields Too Large"
  457. case .unavailableForLegalReasons:
  458. return "Unavailable For Legal Reasons"
  459. case .internalServerError:
  460. return "Internal Server Error"
  461. case .notImplemented:
  462. return "Not Implemented"
  463. case .badGateway:
  464. return "Bad Gateway"
  465. case .serviceUnavailable:
  466. return "Service Unavailable"
  467. case .gatewayTimeout:
  468. return "Gateway Timeout"
  469. case .httpVersionNotSupported:
  470. return "HTTP Version Not Supported"
  471. case .variantAlsoNegotiates:
  472. return "Variant Also Negotiates"
  473. case .insufficientStorage:
  474. return "Insufficient Storage"
  475. case .loopDetected:
  476. return "Loop Detected"
  477. case .notExtended:
  478. return "Not Extended"
  479. case .networkAuthenticationRequired:
  480. return "Network Authentication Required"
  481. case .custom(code: _, reasonPhrase: let phrase):
  482. return phrase
  483. }
  484. }
  485. }