http_status_code.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /* Proposed SG14 status_code
  2. (C) 2022-2024 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
  3. File Created: Jun 2022
  4. Boost Software License - Version 1.0 - August 17th, 2003
  5. Permission is hereby granted, free of charge, to any person or organization
  6. obtaining a copy of the software and accompanying documentation covered by
  7. this license (the "Software") to use, reproduce, display, distribute,
  8. execute, and transmit the Software, and to prepare derivative works of the
  9. Software, and to permit third-parties to whom the Software is furnished to
  10. do so, all subject to the following:
  11. The copyright notices in the Software and this entire statement, including
  12. the above license grant, this restriction and the following disclaimer,
  13. must be included in all copies of the Software, in whole or in part, and
  14. all derivative works of the Software, unless such copies or derivative
  15. works are solely in the form of machine-executable object code generated by
  16. a source language processor.
  17. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
  20. SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
  21. FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
  22. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. DEALINGS IN THE SOFTWARE.
  24. */
  25. #ifndef BOOST_OUTCOME_SYSTEM_ERROR2_HTTP_STATUS_CODE_HPP
  26. #define BOOST_OUTCOME_SYSTEM_ERROR2_HTTP_STATUS_CODE_HPP
  27. #include "status_code.hpp"
  28. BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
  29. class _http_status_code_domain;
  30. //! A HTTP status code.
  31. using http_status_code = status_code<_http_status_code_domain>;
  32. namespace mixins
  33. {
  34. template <class Base> struct mixin<Base, _http_status_code_domain> : public Base
  35. {
  36. using Base::Base;
  37. //! True if the HTTP status code is informational
  38. inline bool is_http_informational() const noexcept;
  39. //! True if the HTTP status code is successful
  40. inline bool is_http_success() const noexcept;
  41. //! True if the HTTP status code is redirection
  42. inline bool is_http_redirection() const noexcept;
  43. //! True if the HTTP status code is client error
  44. inline bool is_http_client_error() const noexcept;
  45. //! True if the HTTP status code is server error
  46. inline bool is_http_server_error() const noexcept;
  47. };
  48. } // namespace mixins
  49. /*! The implementation of the domain for HTTP status codes.
  50. */
  51. class _http_status_code_domain : public status_code_domain
  52. {
  53. template <class DomainType> friend class status_code;
  54. using _base = status_code_domain;
  55. public:
  56. //! The value type of the HTTP code, which is an `int`
  57. using value_type = int;
  58. using _base::string_ref;
  59. //! Default constructor
  60. constexpr explicit _http_status_code_domain(typename _base::unique_id_type id = 0xbdb4cde88378a333ull) noexcept
  61. : _base(id)
  62. {
  63. }
  64. _http_status_code_domain(const _http_status_code_domain &) = default;
  65. _http_status_code_domain(_http_status_code_domain &&) = default;
  66. _http_status_code_domain &operator=(const _http_status_code_domain &) = default;
  67. _http_status_code_domain &operator=(_http_status_code_domain &&) = default;
  68. ~_http_status_code_domain() = default;
  69. //! Constexpr singleton getter. Returns constexpr http_status_code_domain variable.
  70. static inline constexpr const _http_status_code_domain &get();
  71. virtual string_ref name() const noexcept override { return string_ref("HTTP status domain"); } // NOLINT
  72. virtual payload_info_t payload_info() const noexcept override
  73. {
  74. return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
  75. (alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
  76. }
  77. protected:
  78. virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
  79. {
  80. assert(code.domain() == *this); // NOLINT
  81. return static_cast<const http_status_code &>(code).value() >= 400; // NOLINT
  82. }
  83. virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT
  84. {
  85. assert(code1.domain() == *this); // NOLINT
  86. const auto &c1 = static_cast<const http_status_code &>(code1); // NOLINT
  87. if(code2.domain() == *this)
  88. {
  89. const auto &c2 = static_cast<const http_status_code &>(code2); // NOLINT
  90. return c1.value() == c2.value();
  91. }
  92. return false;
  93. }
  94. virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT
  95. {
  96. assert(code.domain() == *this); // NOLINT
  97. const auto &c = static_cast<const http_status_code &>(code); // NOLINT
  98. switch(c.value())
  99. {
  100. case 102:
  101. case 202:
  102. return errc::operation_in_progress;
  103. case 400:
  104. return errc::invalid_argument;
  105. case 401:
  106. return errc::operation_not_permitted;
  107. case 403:
  108. return errc::permission_denied;
  109. case 404:
  110. case 410:
  111. return errc::no_such_file_or_directory;
  112. case 405:
  113. case 418:
  114. return errc::operation_not_supported;
  115. case 406:
  116. return errc::protocol_not_supported;
  117. case 408:
  118. return errc::timed_out;
  119. case 413:
  120. return errc::result_out_of_range;
  121. case 501:
  122. return errc::not_supported;
  123. case 503:
  124. return errc::resource_unavailable_try_again;
  125. case 504:
  126. return errc::timed_out;
  127. case 507:
  128. return errc::no_space_on_device;
  129. default:
  130. return errc::unknown;
  131. }
  132. }
  133. virtual string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT
  134. {
  135. assert(code.domain() == *this); // NOLINT
  136. const auto &c = static_cast<const http_status_code &>(code); // NOLINT
  137. return string_ref(
  138. [&]() -> const char *
  139. {
  140. switch(c.value())
  141. {
  142. case 100:
  143. return "Continue";
  144. case 101:
  145. return "Switching Protocols";
  146. case 102:
  147. return "Processing";
  148. case 103:
  149. return "Early Hints";
  150. case 200:
  151. return "OK";
  152. case 201:
  153. return "Created";
  154. case 202:
  155. return "Accepted";
  156. case 203:
  157. return "Non-Authoritative Information";
  158. case 204:
  159. return "No Content";
  160. case 205:
  161. return "Reset Content";
  162. case 206:
  163. return "Partial Content";
  164. case 207:
  165. return "Multi-Status";
  166. case 208:
  167. return "Already Reported";
  168. case 209:
  169. return "IM Used";
  170. case 300:
  171. return "Multiple Choices";
  172. case 301:
  173. return "Moved Permanently";
  174. case 302:
  175. return "Found";
  176. case 303:
  177. return "See Other";
  178. case 304:
  179. return "Not Modified";
  180. case 305:
  181. return "Use Proxy";
  182. case 306:
  183. return "Switch Proxy";
  184. case 307:
  185. return "Temporary Redirect";
  186. case 308:
  187. return "Permanent Redirect";
  188. case 400:
  189. return "Bad Request";
  190. case 401:
  191. return "Unauthorized";
  192. case 402:
  193. return "Payment Required";
  194. case 403:
  195. return "Forbidden";
  196. case 404:
  197. return "Not Found";
  198. case 405:
  199. return "Method Not Allowed";
  200. case 406:
  201. return "Not Acceptable";
  202. case 407:
  203. return "Proxy Authentication Required";
  204. case 408:
  205. return "Request Timeout";
  206. case 409:
  207. return "Conflict";
  208. case 410:
  209. return "Gone";
  210. case 411:
  211. return "Length Required";
  212. case 412:
  213. return "Precondition Failed";
  214. case 413:
  215. return "Payload Too Large";
  216. case 414:
  217. return "URI Too Long";
  218. case 415:
  219. return "Unsupported Media Type";
  220. case 416:
  221. return "Range Not Satisfiable";
  222. case 417:
  223. return "Expectation Failed";
  224. case 418:
  225. return "I'm a teapot";
  226. case 421:
  227. return "Misdirected Request";
  228. case 422:
  229. return "Unprocessable Entity";
  230. case 423:
  231. return "Locked";
  232. case 424:
  233. return "Failed Dependency";
  234. case 425:
  235. return "Too Early";
  236. case 426:
  237. return "Upgrade Required";
  238. case 428:
  239. return "Precondition Required";
  240. case 429:
  241. return "Too Many Requests";
  242. case 431:
  243. return "Request Header Fields Too Large";
  244. case 451:
  245. return "Unavailable For Legal Reasons";
  246. case 500:
  247. return "Internal Server Error";
  248. case 501:
  249. return "Not Implemented";
  250. case 502:
  251. return "Bad Gateway";
  252. case 503:
  253. return "Service Unavailable";
  254. case 504:
  255. return "Gateway Timeout";
  256. case 505:
  257. return "HTTP Version Not Supported";
  258. case 506:
  259. return "Variant Also Negotiates";
  260. case 507:
  261. return "Insufficient Storage";
  262. case 508:
  263. return "Loop Detected";
  264. case 510:
  265. return "Not Extended";
  266. case 511:
  267. return "Network Authentication Required";
  268. default:
  269. return "Unknown";
  270. }
  271. }());
  272. }
  273. #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
  274. BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT
  275. {
  276. assert(code.domain() == *this); // NOLINT
  277. const auto &c = static_cast<const http_status_code &>(code); // NOLINT
  278. throw status_error<_http_status_code_domain>(c);
  279. }
  280. #endif
  281. };
  282. //! A constexpr source variable for the `getaddrinfo()` code domain, which is that of `getaddrinfo()`. Returned by `_http_status_code_domain::get()`.
  283. constexpr _http_status_code_domain http_status_code_domain;
  284. inline constexpr const _http_status_code_domain &_http_status_code_domain::get()
  285. {
  286. return http_status_code_domain;
  287. }
  288. namespace mixins
  289. {
  290. template <class Base> inline bool mixin<Base, _http_status_code_domain>::is_http_informational() const noexcept
  291. {
  292. const auto &c = static_cast<const http_status_code *>(this)->value();
  293. return c >= 100 && c < 200;
  294. }
  295. template <class Base> inline bool mixin<Base, _http_status_code_domain>::is_http_success() const noexcept
  296. {
  297. const auto &c = static_cast<const http_status_code *>(this)->value();
  298. return c >= 200 && c < 300;
  299. }
  300. template <class Base> inline bool mixin<Base, _http_status_code_domain>::is_http_redirection() const noexcept
  301. {
  302. const auto &c = static_cast<const http_status_code *>(this)->value();
  303. return c >= 300 && c < 400;
  304. }
  305. template <class Base> inline bool mixin<Base, _http_status_code_domain>::is_http_client_error() const noexcept
  306. {
  307. const auto &c = static_cast<const http_status_code *>(this)->value();
  308. return c >= 400 && c < 500;
  309. }
  310. template <class Base> inline bool mixin<Base, _http_status_code_domain>::is_http_server_error() const noexcept
  311. {
  312. const auto &c = static_cast<const http_status_code *>(this)->value();
  313. return c >= 500 && c < 600;
  314. }
  315. } // namespace mixins
  316. BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
  317. #endif