HTTPResponseStatus.swift 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  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),
  224. (.custom, _):
  225. return false
  226. default:
  227. return lhs.code == rhs.code
  228. }
  229. }
  230. }
  231. public extension HTTPResponseStatus {
  232. /// The numerical status code for a given HTTP response status.
  233. var code: UInt {
  234. switch self {
  235. case .continue:
  236. return 100
  237. case .switchingProtocols:
  238. return 101
  239. case .processing:
  240. return 102
  241. case .ok:
  242. return 200
  243. case .created:
  244. return 201
  245. case .accepted:
  246. return 202
  247. case .nonAuthoritativeInformation:
  248. return 203
  249. case .noContent:
  250. return 204
  251. case .resetContent:
  252. return 205
  253. case .partialContent:
  254. return 206
  255. case .multiStatus:
  256. return 207
  257. case .alreadyReported:
  258. return 208
  259. case .imUsed:
  260. return 226
  261. case .multipleChoices:
  262. return 300
  263. case .movedPermanently:
  264. return 301
  265. case .found:
  266. return 302
  267. case .seeOther:
  268. return 303
  269. case .notModified:
  270. return 304
  271. case .useProxy:
  272. return 305
  273. case .temporaryRedirect:
  274. return 307
  275. case .permanentRedirect:
  276. return 308
  277. case .badRequest:
  278. return 400
  279. case .unauthorized:
  280. return 401
  281. case .paymentRequired:
  282. return 402
  283. case .forbidden:
  284. return 403
  285. case .notFound:
  286. return 404
  287. case .methodNotAllowed:
  288. return 405
  289. case .notAcceptable:
  290. return 406
  291. case .proxyAuthenticationRequired:
  292. return 407
  293. case .requestTimeout:
  294. return 408
  295. case .conflict:
  296. return 409
  297. case .gone:
  298. return 410
  299. case .lengthRequired:
  300. return 411
  301. case .preconditionFailed:
  302. return 412
  303. case .payloadTooLarge:
  304. return 413
  305. case .uriTooLong:
  306. return 414
  307. case .unsupportedMediaType:
  308. return 415
  309. case .rangeNotSatisfiable:
  310. return 416
  311. case .expectationFailed:
  312. return 417
  313. case .imATeapot:
  314. return 418
  315. case .misdirectedRequest:
  316. return 421
  317. case .unprocessableEntity:
  318. return 422
  319. case .locked:
  320. return 423
  321. case .failedDependency:
  322. return 424
  323. case .upgradeRequired:
  324. return 426
  325. case .preconditionRequired:
  326. return 428
  327. case .tooManyRequests:
  328. return 429
  329. case .requestHeaderFieldsTooLarge:
  330. return 431
  331. case .unavailableForLegalReasons:
  332. return 451
  333. case .internalServerError:
  334. return 500
  335. case .notImplemented:
  336. return 501
  337. case .badGateway:
  338. return 502
  339. case .serviceUnavailable:
  340. return 503
  341. case .gatewayTimeout:
  342. return 504
  343. case .httpVersionNotSupported:
  344. return 505
  345. case .variantAlsoNegotiates:
  346. return 506
  347. case .insufficientStorage:
  348. return 507
  349. case .loopDetected:
  350. return 508
  351. case .notExtended:
  352. return 510
  353. case .networkAuthenticationRequired:
  354. return 511
  355. case .custom(code: let code, reasonPhrase: _):
  356. return code
  357. }
  358. }
  359. /// The string reason phrase for a given HTTP response status.
  360. var reasonPhrase: String {
  361. switch self {
  362. case .continue:
  363. return "Continue"
  364. case .switchingProtocols:
  365. return "Switching Protocols"
  366. case .processing:
  367. return "Processing"
  368. case .ok:
  369. return "OK"
  370. case .created:
  371. return "Created"
  372. case .accepted:
  373. return "Accepted"
  374. case .nonAuthoritativeInformation:
  375. return "Non-Authoritative Information"
  376. case .noContent:
  377. return "No Content"
  378. case .resetContent:
  379. return "Reset Content"
  380. case .partialContent:
  381. return "Partial Content"
  382. case .multiStatus:
  383. return "Multi-Status"
  384. case .alreadyReported:
  385. return "Already Reported"
  386. case .imUsed:
  387. return "IM Used"
  388. case .multipleChoices:
  389. return "Multiple Choices"
  390. case .movedPermanently:
  391. return "Moved Permanently"
  392. case .found:
  393. return "Found"
  394. case .seeOther:
  395. return "See Other"
  396. case .notModified:
  397. return "Not Modified"
  398. case .useProxy:
  399. return "Use Proxy"
  400. case .temporaryRedirect:
  401. return "Temporary Redirect"
  402. case .permanentRedirect:
  403. return "Permanent Redirect"
  404. case .badRequest:
  405. return "Bad Request"
  406. case .unauthorized:
  407. return "Unauthorized"
  408. case .paymentRequired:
  409. return "Payment Required"
  410. case .forbidden:
  411. return "Forbidden"
  412. case .notFound:
  413. return "Not Found"
  414. case .methodNotAllowed:
  415. return "Method Not Allowed"
  416. case .notAcceptable:
  417. return "Not Acceptable"
  418. case .proxyAuthenticationRequired:
  419. return "Proxy Authentication Required"
  420. case .requestTimeout:
  421. return "Request Timeout"
  422. case .conflict:
  423. return "Conflict"
  424. case .gone:
  425. return "Gone"
  426. case .lengthRequired:
  427. return "Length Required"
  428. case .preconditionFailed:
  429. return "Precondition Failed"
  430. case .payloadTooLarge:
  431. return "Payload Too Large"
  432. case .uriTooLong:
  433. return "URI Too Long"
  434. case .unsupportedMediaType:
  435. return "Unsupported Media Type"
  436. case .rangeNotSatisfiable:
  437. return "Range Not Satisfiable"
  438. case .expectationFailed:
  439. return "Expectation Failed"
  440. case .imATeapot:
  441. return "I'm a teapot"
  442. case .misdirectedRequest:
  443. return "Misdirected Request"
  444. case .unprocessableEntity:
  445. return "Unprocessable Entity"
  446. case .locked:
  447. return "Locked"
  448. case .failedDependency:
  449. return "Failed Dependency"
  450. case .upgradeRequired:
  451. return "Upgrade Required"
  452. case .preconditionRequired:
  453. return "Precondition Required"
  454. case .tooManyRequests:
  455. return "Too Many Requests"
  456. case .requestHeaderFieldsTooLarge:
  457. return "Request Header Fields Too Large"
  458. case .unavailableForLegalReasons:
  459. return "Unavailable For Legal Reasons"
  460. case .internalServerError:
  461. return "Internal Server Error"
  462. case .notImplemented:
  463. return "Not Implemented"
  464. case .badGateway:
  465. return "Bad Gateway"
  466. case .serviceUnavailable:
  467. return "Service Unavailable"
  468. case .gatewayTimeout:
  469. return "Gateway Timeout"
  470. case .httpVersionNotSupported:
  471. return "HTTP Version Not Supported"
  472. case .variantAlsoNegotiates:
  473. return "Variant Also Negotiates"
  474. case .insufficientStorage:
  475. return "Insufficient Storage"
  476. case .loopDetected:
  477. return "Loop Detected"
  478. case .notExtended:
  479. return "Not Extended"
  480. case .networkAuthenticationRequired:
  481. return "Network Authentication Required"
  482. case .custom(code: _, reasonPhrase: let phrase):
  483. return phrase
  484. }
  485. }
  486. }