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