close.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. /*
  2. * Copyright (c) 2014, Peter Thorson. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. * * Redistributions of source code must retain the above copyright
  7. * notice, this list of conditions and the following disclaimer.
  8. * * Redistributions in binary form must reproduce the above copyright
  9. * notice, this list of conditions and the following disclaimer in the
  10. * documentation and/or other materials provided with the distribution.
  11. * * Neither the name of the WebSocket++ Project nor the
  12. * names of its contributors may be used to endorse or promote products
  13. * derived from this software without specific prior written permission.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
  19. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  20. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  21. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  22. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  24. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. *
  26. */
  27. #ifndef WEBSOCKETPP_CLOSE_HPP
  28. #define WEBSOCKETPP_CLOSE_HPP
  29. /** \file
  30. * A package of types and methods for manipulating WebSocket close codes.
  31. */
  32. #include <websocketpp/error.hpp>
  33. #include <websocketpp/common/network.hpp>
  34. #include <websocketpp/common/stdint.hpp>
  35. #include <websocketpp/utf8_validator.hpp>
  36. #include <string>
  37. namespace websocketpp {
  38. /// A package of types and methods for manipulating WebSocket close codes.
  39. namespace close {
  40. /// A package of types and methods for manipulating WebSocket close status'
  41. namespace status {
  42. /// The type of a close code value.
  43. typedef uint16_t value;
  44. /// A blank value for internal use.
  45. static value const blank = 0;
  46. /// Close the connection without a WebSocket close handshake.
  47. /**
  48. * This special value requests that the WebSocket connection be closed
  49. * without performing the WebSocket closing handshake. This does not comply
  50. * with RFC6455, but should be safe to do if necessary. This could be useful
  51. * for clients that need to disconnect quickly and cannot afford the
  52. * complete handshake.
  53. */
  54. static value const omit_handshake = 1;
  55. /// Close the connection with a forced TCP drop.
  56. /**
  57. * This special value requests that the WebSocket connection be closed by
  58. * forcibly dropping the TCP connection. This will leave the other side of
  59. * the connection with a broken connection and some expensive timeouts. this
  60. * should not be done except in extreme cases or in cases of malicious
  61. * remote endpoints.
  62. */
  63. static value const force_tcp_drop = 2;
  64. /// Normal closure, meaning that the purpose for which the connection was
  65. /// established has been fulfilled.
  66. static value const normal = 1000;
  67. /// The endpoint was "going away", such as a server going down or a browser
  68. /// navigating away from a page.
  69. static value const going_away = 1001;
  70. /// A protocol error occurred.
  71. static value const protocol_error = 1002;
  72. /// The connection was terminated because an endpoint received a type of
  73. /// data it cannot accept.
  74. /**
  75. * (e.g., an endpoint that understands only text data MAY send this if it
  76. * receives a binary message).
  77. */
  78. static value const unsupported_data = 1003;
  79. /// A dummy value to indicate that no status code was received.
  80. /**
  81. * This value is illegal on the wire.
  82. */
  83. static value const no_status = 1005;
  84. /// A dummy value to indicate that the connection was closed abnormally.
  85. /**
  86. * In such a case there was no close frame to extract a value from. This
  87. * value is illegal on the wire.
  88. */
  89. static value const abnormal_close = 1006;
  90. /// An endpoint received message data inconsistent with its type.
  91. /**
  92. * For example: Invalid UTF8 bytes in a text message.
  93. */
  94. static value const invalid_payload = 1007;
  95. /// An endpoint received a message that violated its policy.
  96. /**
  97. * This is a generic status code that can be returned when there is no other
  98. * more suitable status code (e.g., 1003 or 1009) or if there is a need to
  99. * hide specific details about the policy.
  100. */
  101. static value const policy_violation = 1008;
  102. /// An endpoint received a message too large to process.
  103. static value const message_too_big = 1009;
  104. /// A client expected the server to accept a required extension request
  105. /**
  106. * The list of extensions that are needed SHOULD appear in the /reason/ part
  107. * of the Close frame. Note that this status code is not used by the server,
  108. * because it can fail the WebSocket handshake instead.
  109. */
  110. static value const extension_required = 1010;
  111. /// An endpoint encountered an unexpected condition that prevented it from
  112. /// fulfilling the request.
  113. static value const internal_endpoint_error = 1011;
  114. /// Indicates that the service is restarted. A client may reconnect and if
  115. /// if it chooses to do so, should reconnect using a randomized delay of
  116. /// 5-30s
  117. static value const service_restart = 1012;
  118. /// Indicates that the service is experiencing overload. A client should
  119. /// only connect to a different IP (when there are multiple for the target)
  120. /// or reconnect to the same IP upon user action.
  121. static value const try_again_later = 1013;
  122. /// Indicates that the server was acting as a gateway or proxy and received
  123. /// an invalid response from the upstream server. This is similar to 502
  124. /// HTTP Status Code.
  125. static value const bad_gateway = 1014;
  126. /// An endpoint failed to perform a TLS handshake
  127. /**
  128. * Designated for use in applications expecting a status code to indicate
  129. * that the connection was closed due to a failure to perform a TLS
  130. * handshake (e.g., the server certificate can't be verified). This value is
  131. * illegal on the wire.
  132. */
  133. static value const tls_handshake = 1015;
  134. /// A generic subprotocol error
  135. /**
  136. * Indicates that a subprotocol error occurred. Typically this involves
  137. * receiving a message that is not formatted as a valid message for the
  138. * subprotocol in use.
  139. */
  140. static value const subprotocol_error = 3000;
  141. /// A invalid subprotocol data
  142. /**
  143. * Indicates that data was received that violated the specification of the
  144. * subprotocol in use.
  145. */
  146. static value const invalid_subprotocol_data = 3001;
  147. /// First value in range reserved for future protocol use
  148. static value const rsv_start = 1016;
  149. /// Last value in range reserved for future protocol use
  150. static value const rsv_end = 2999;
  151. /// Test whether a close code is in a reserved range
  152. /**
  153. * @param [in] code The code to test
  154. * @return Whether or not code is reserved
  155. */
  156. inline bool reserved(value code) {
  157. return ((code >= rsv_start && code <= rsv_end) ||
  158. code == 1004);
  159. }
  160. /// First value in range that is always invalid on the wire
  161. static value const invalid_low = 999;
  162. /// Last value in range that is always invalid on the wire
  163. static value const invalid_high = 5000;
  164. /// Test whether a close code is invalid on the wire
  165. /**
  166. * @param [in] code The code to test
  167. * @return Whether or not code is invalid on the wire
  168. */
  169. inline bool invalid(value code) {
  170. return (code <= invalid_low || code >= invalid_high ||
  171. code == no_status || code == abnormal_close ||
  172. code == tls_handshake);
  173. }
  174. /// Determine if the code represents an unrecoverable error
  175. /**
  176. * There is a class of errors for which once they are discovered normal
  177. * WebSocket functionality can no longer occur. This function determines
  178. * if a given code is one of these values. This information is used to
  179. * determine if the system has the capability of waiting for a close
  180. * acknowledgement or if it should drop the TCP connection immediately
  181. * after sending its close frame.
  182. *
  183. * @param [in] code The value to test.
  184. * @return True if the code represents an unrecoverable error
  185. */
  186. inline bool terminal(value code) {
  187. return (code == protocol_error || code == invalid_payload ||
  188. code == policy_violation || code == message_too_big ||
  189. code == internal_endpoint_error);
  190. }
  191. /// Return a human readable interpretation of a WebSocket close code
  192. /**
  193. * See https://tools.ietf.org/html/rfc6455#section-7.4 for more details.
  194. *
  195. * @since 0.3.0
  196. *
  197. * @param [in] code The code to look up.
  198. * @return A human readable interpretation of the code.
  199. */
  200. inline std::string get_string(value code) {
  201. switch (code) {
  202. case normal:
  203. return "Normal close";
  204. case going_away:
  205. return "Going away";
  206. case protocol_error:
  207. return "Protocol error";
  208. case unsupported_data:
  209. return "Unsupported data";
  210. case no_status:
  211. return "No status set";
  212. case abnormal_close:
  213. return "Abnormal close";
  214. case invalid_payload:
  215. return "Invalid payload";
  216. case policy_violation:
  217. return "Policy violoation";
  218. case message_too_big:
  219. return "Message too big";
  220. case extension_required:
  221. return "Extension required";
  222. case internal_endpoint_error:
  223. return "Internal endpoint error";
  224. case service_restart:
  225. return "Service restart";
  226. case try_again_later:
  227. return "Try again later";
  228. case bad_gateway:
  229. return "Bad gateway";
  230. case tls_handshake:
  231. return "TLS handshake failure";
  232. case subprotocol_error:
  233. return "Generic subprotocol error";
  234. case invalid_subprotocol_data:
  235. return "Invalid subprotocol data";
  236. default:
  237. return "Unknown";
  238. }
  239. }
  240. } // namespace status
  241. /// Type used to convert close statuses between integer and wire representations
  242. union code_converter {
  243. uint16_t i;
  244. char c[2];
  245. };
  246. /// Extract a close code value from a close payload
  247. /**
  248. * If there is no close value (ie string is empty) status::no_status is
  249. * returned. If a code couldn't be extracted (usually do to a short or
  250. * otherwise mangled payload) status::protocol_error is returned and the ec
  251. * value is flagged as an error. Note that this case is different than the case
  252. * where protocol error is received over the wire.
  253. *
  254. * If the value is in an invalid or reserved range ec is set accordingly.
  255. *
  256. * @param [in] payload Close frame payload value received over the wire.
  257. * @param [out] ec Set to indicate what error occurred, if any.
  258. * @return The extracted value
  259. */
  260. inline status::value extract_code(std::string const & payload, lib::error_code
  261. & ec)
  262. {
  263. ec = lib::error_code();
  264. if (payload.size() == 0) {
  265. return status::no_status;
  266. } else if (payload.size() == 1) {
  267. ec = make_error_code(error::bad_close_code);
  268. return status::protocol_error;
  269. }
  270. code_converter val;
  271. val.c[0] = payload[0];
  272. val.c[1] = payload[1];
  273. status::value code(ntohs(val.i));
  274. if (status::invalid(code)) {
  275. ec = make_error_code(error::invalid_close_code);
  276. }
  277. if (status::reserved(code)) {
  278. ec = make_error_code(error::reserved_close_code);
  279. }
  280. return code;
  281. }
  282. /// Extract the reason string from a close payload
  283. /**
  284. * The string should be a valid UTF8 message. error::invalid_utf8 will be set if
  285. * the function extracts a reason that is not valid UTF8.
  286. *
  287. * @param [in] payload The payload string to extract a reason from.
  288. * @param [out] ec Set to indicate what error occurred, if any.
  289. * @return The reason string.
  290. */
  291. inline std::string extract_reason(std::string const & payload, lib::error_code
  292. & ec)
  293. {
  294. std::string reason;
  295. ec = lib::error_code();
  296. if (payload.size() > 2) {
  297. reason.append(payload.begin()+2,payload.end());
  298. }
  299. if (!websocketpp::utf8_validator::validate(reason)) {
  300. ec = make_error_code(error::invalid_utf8);
  301. }
  302. return reason;
  303. }
  304. } // namespace close
  305. } // namespace websocketpp
  306. #endif // WEBSOCKETPP_CLOSE_HPP