WebSocket++  0.8.3-dev
C++ websocket client/server library
close.hpp
Go to the documentation of this file.
1 
2 /*
3  * Copyright (c) 2014, Peter Thorson. All rights reserved.
4  *
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.
15  *
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.
26  *
27  */
28 
29 #ifndef WEBSOCKETPP_CLOSE_HPP
30 #define WEBSOCKETPP_CLOSE_HPP
31 
32 /** \file
33  * A package of types and methods for manipulating WebSocket close codes.
34  */
35 
36 #include <websocketpp/error.hpp>
37 #include <websocketpp/common/network.hpp>
38 #include <websocketpp/common/stdint.hpp>
39 #include <websocketpp/utf8_validator.hpp>
40 
41 #include <string>
42 
43 namespace websocketpp {
44 /// A package of types and methods for manipulating WebSocket close codes.
45 namespace close {
46 /// A package of types and methods for manipulating WebSocket close status'
47 namespace status {
48  /// The type of a close code value.
49  typedef uint16_t value;
50 
51  /// A blank value for internal use.
52  static value const blank = 0;
53 
54  /// Close the connection without a WebSocket close handshake.
55  /**
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
60  * complete handshake.
61  */
62  static value const omit_handshake = 1;
63 
64  /// Close the connection with a forced TCP drop.
65  /**
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
70  * remote endpoints.
71  */
72  static value const force_tcp_drop = 2;
73 
74  /// Normal closure, meaning that the purpose for which the connection was
75  /// established has been fulfilled.
76  static value const normal = 1000;
77 
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;
81 
82  /// A protocol error occurred.
83  static value const protocol_error = 1002;
84 
85  /// The connection was terminated because an endpoint received a type of
86  /// data it cannot accept.
87  /**
88  * (e.g., an endpoint that understands only text data MAY send this if it
89  * receives a binary message).
90  */
91  static value const unsupported_data = 1003;
92 
93  /// A dummy value to indicate that no status code was received.
94  /**
95  * This value is illegal on the wire.
96  */
97  static value const no_status = 1005;
98 
99  /// A dummy value to indicate that the connection was closed abnormally.
100  /**
101  * In such a case there was no close frame to extract a value from. This
102  * value is illegal on the wire.
103  */
104  static value const abnormal_close = 1006;
105 
106  /// An endpoint received message data inconsistent with its type.
107  /**
108  * For example: Invalid UTF8 bytes in a text message.
109  */
110  static value const invalid_payload = 1007;
111 
112  /// An endpoint received a message that violated its policy.
113  /**
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.
117  */
118  static value const policy_violation = 1008;
119 
120  /// An endpoint received a message too large to process.
121  static value const message_too_big = 1009;
122 
123  /// A client expected the server to accept a required extension request
124  /**
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.
128  */
129  static value const extension_required = 1010;
130 
131  /// An endpoint encountered an unexpected condition that prevented it from
132  /// fulfilling the request.
133  static value const internal_endpoint_error = 1011;
134 
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
137  /// 5-30s
138  static value const service_restart = 1012;
139 
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;
144 
145  /// Indicates that the server was acting as a gateway or proxy and received
146  /// an invalid response from the upstream server. This is similar to 502
147  /// HTTP Status Code.
148  static value const bad_gateway = 1014;
149 
150  /// An endpoint failed to perform a TLS handshake
151  /**
152  * Designated for use in applications expecting a status code to indicate
153  * that the connection was closed due to a failure to perform a TLS
154  * handshake (e.g., the server certificate can't be verified). This value is
155  * illegal on the wire.
156  */
157  static value const tls_handshake = 1015;
158 
159  /// A generic subprotocol error
160  /**
161  * Indicates that a subprotocol error occurred. Typically this involves
162  * receiving a message that is not formatted as a valid message for the
163  * subprotocol in use.
164  */
165  static value const subprotocol_error = 3000;
166 
167  /// A invalid subprotocol data
168  /**
169  * Indicates that data was received that violated the specification of the
170  * subprotocol in use.
171  */
172  static value const invalid_subprotocol_data = 3001;
173 
174  /// First value in range reserved for future protocol use
175  static value const rsv_start = 1016;
176  /// Last value in range reserved for future protocol use
177  static value const rsv_end = 2999;
178 
179  /// Test whether a close code is in a reserved range
180  /**
181  * @param [in] code The code to test
182  * @return Whether or not code is reserved
183  */
184  inline bool reserved(value code) {
185  return ((code >= rsv_start && code <= rsv_end) ||
186  code == 1004);
187  }
188 
189  /// First value in range that is always invalid on the wire
190  static value const invalid_low = 999;
191  /// Last value in range that is always invalid on the wire
192  static value const invalid_high = 5000;
193 
194  /// Test whether a close code is invalid on the wire
195  /**
196  * @param [in] code The code to test
197  * @return Whether or not code is invalid on the wire
198  */
199  inline bool invalid(value code) {
200  return (code <= invalid_low || code >= invalid_high ||
201  code == no_status || code == abnormal_close ||
202  code == tls_handshake);
203  }
204 
205  /// Determine if the code represents an unrecoverable error
206  /**
207  * There is a class of errors for which once they are discovered normal
208  * WebSocket functionality can no longer occur. This function determines
209  * if a given code is one of these values. This information is used to
210  * determine if the system has the capability of waiting for a close
211  * acknowledgement or if it should drop the TCP connection immediately
212  * after sending its close frame.
213  *
214  * @param [in] code The value to test.
215  * @return True if the code represents an unrecoverable error
216  */
217  inline bool terminal(value code) {
218  return (code == protocol_error || code == invalid_payload ||
219  code == policy_violation || code == message_too_big ||
220  code == internal_endpoint_error);
221  }
222 
223  /// Return a human readable interpretation of a WebSocket close code
224  /**
225  * See https://tools.ietf.org/html/rfc6455#section-7.4 for more details.
226  *
227  * @since 0.3.0
228  *
229  * @param [in] code The code to look up.
230  * @return A human readable interpretation of the code.
231  */
233  switch (code) {
234  case normal:
235  return "Normal close";
236  case going_away:
237  return "Going away";
238  case protocol_error:
239  return "Protocol error";
240  case unsupported_data:
241  return "Unsupported data";
242  case no_status:
243  return "No status set";
244  case abnormal_close:
245  return "Abnormal close";
246  case invalid_payload:
247  return "Invalid payload";
248  case policy_violation:
249  return "Policy violoation";
250  case message_too_big:
251  return "Message too big";
252  case extension_required:
253  return "Extension required";
254  case internal_endpoint_error:
255  return "Internal endpoint error";
256  case service_restart:
257  return "Service restart";
258  case try_again_later:
259  return "Try again later";
260  case bad_gateway:
261  return "Bad gateway";
262  case tls_handshake:
263  return "TLS handshake failure";
264  case subprotocol_error:
265  return "Generic subprotocol error";
266  case invalid_subprotocol_data:
267  return "Invalid subprotocol data";
268  default:
269  return "Unknown";
270  }
271  }
272 } // namespace status
273 
274 /// Type used to convert close statuses between integer and wire representations
276  uint16_t i;
277  char c[2];
278 };
279 
280 /// Extract a close code value from a close payload
281 /**
282  * If there is no close value (ie string is empty) status::no_status is
283  * returned. If a code couldn't be extracted (usually do to a short or
284  * otherwise mangled payload) status::protocol_error is returned and the ec
285  * value is flagged as an error. Note that this case is different than the case
286  * where protocol error is received over the wire.
287  *
288  * If the value is in an invalid or reserved range ec is set accordingly.
289  *
290  * @param [in] payload Close frame payload value received over the wire.
291  * @param [out] ec Set to indicate what error occurred, if any.
292  * @return The extracted value
293  */
294 inline status::value extract_code(std::string const & payload, lib::error_code
295  & ec)
296 {
297  ec = lib::error_code();
298 
299  if (payload.size() == 0) {
300  return status::no_status;
301  } else if (payload.size() == 1) {
302  ec = make_error_code(error::bad_close_code);
303  return status::protocol_error;
304  }
305 
306  code_converter val;
307 
308  val.c[0] = payload[0];
309  val.c[1] = payload[1];
310 
311  status::value code(ntohs(val.i));
312 
313  if (status::invalid(code)) {
314  ec = make_error_code(error::invalid_close_code);
315  }
316 
317  if (status::reserved(code)) {
318  ec = make_error_code(error::reserved_close_code);
319  }
320 
321  return code;
322 }
323 
324 /// Extract the reason string from a close payload
325 /**
326  * The string should be a valid UTF8 message. error::invalid_utf8 will be set if
327  * the function extracts a reason that is not valid UTF8.
328  *
329  * @param [in] payload The payload string to extract a reason from.
330  * @param [out] ec Set to indicate what error occurred, if any.
331  * @return The reason string.
332  */
334  & ec)
335 {
336  std::string reason;
337  ec = lib::error_code();
338 
339  if (payload.size() > 2) {
340  reason.append(payload.begin()+2,payload.end());
341  }
342 
343  if (!websocketpp::utf8_validator::validate(reason)) {
344  ec = make_error_code(error::invalid_utf8);
345  }
346 
347  return reason;
348 }
349 
350 } // namespace close
351 } // namespace websocketpp
352 
353 #endif // WEBSOCKETPP_CLOSE_HPP
websocketpp::close::status::blank
static value const blank
A blank value for internal use.
Definition: close.hpp:52
websocketpp::close::code_converter
Type used to convert close statuses between integer and wire representations.
Definition: close.hpp:275
websocketpp::close::status::protocol_error
static value const protocol_error
A protocol error occurred.
Definition: close.hpp:83
websocketpp::close::status::extension_required
static value const extension_required
A client expected the server to accept a required extension request.
Definition: close.hpp:129
websocketpp::close::status::try_again_later
static value const try_again_later
Definition: close.hpp:143
websocketpp::close::status::subprotocol_error
static value const subprotocol_error
A generic subprotocol error.
Definition: close.hpp:165
websocketpp::close::status::invalid_payload
static value const invalid_payload
An endpoint received message data inconsistent with its type.
Definition: close.hpp:110
websocketpp::close::status::invalid
bool invalid(value code)
Test whether a close code is invalid on the wire.
Definition: close.hpp:199
websocketpp::close::status::bad_gateway
static value const bad_gateway
Definition: close.hpp:148
websocketpp::close::status::normal
static value const normal
Definition: close.hpp:76
websocketpp::close::status::policy_violation
static value const policy_violation
An endpoint received a message that violated its policy.
Definition: close.hpp:118
websocketpp::close::status::value
uint16_t value
The type of a close code value.
Definition: close.hpp:49
websocketpp::close::extract_code
status::value extract_code(std::string const &payload, lib::error_code &ec)
Extract a close code value from a close payload.
Definition: close.hpp:294
websocketpp::close::status::invalid_low
static value const invalid_low
First value in range that is always invalid on the wire.
Definition: close.hpp:190
websocketpp::close::status::invalid_high
static value const invalid_high
Last value in range that is always invalid on the wire.
Definition: close.hpp:192
websocketpp::close::status::tls_handshake
static value const tls_handshake
An endpoint failed to perform a TLS handshake.
Definition: close.hpp:157
websocketpp::close::status::unsupported_data
static value const unsupported_data
Definition: close.hpp:91
websocketpp::close::status::reserved
bool reserved(value code)
Test whether a close code is in a reserved range.
Definition: close.hpp:184
websocketpp::close::status::invalid_subprotocol_data
static value const invalid_subprotocol_data
A invalid subprotocol data.
Definition: close.hpp:172
websocketpp::versions_supported
static std::vector< int > const versions_supported(helper, helper+4)
Container that stores the list of protocol versions supported.
websocketpp::close
A package of types and methods for manipulating WebSocket close codes.
Definition: close.hpp:45
websocketpp::close::extract_reason
std::string extract_reason(std::string const &payload, lib::error_code &ec)
Extract the reason string from a close payload.
Definition: close.hpp:333
websocketpp::close::status::get_string
std::string get_string(value code)
Return a human readable interpretation of a WebSocket close code.
Definition: close.hpp:232
websocketpp::close::status
A package of types and methods for manipulating WebSocket close status'.
Definition: close.hpp:47
websocketpp::close::status::rsv_start
static value const rsv_start
First value in range reserved for future protocol use.
Definition: close.hpp:175
websocketpp::close::status::service_restart
static value const service_restart
Definition: close.hpp:138
websocketpp::close::status::abnormal_close
static value const abnormal_close
A dummy value to indicate that the connection was closed abnormally.
Definition: close.hpp:104
websocketpp::close::status::going_away
static value const going_away
Definition: close.hpp:80
websocketpp::close::status::omit_handshake
static value const omit_handshake
Close the connection without a WebSocket close handshake.
Definition: close.hpp:62
websocketpp::close::status::rsv_end
static value const rsv_end
Last value in range reserved for future protocol use.
Definition: close.hpp:177
websocketpp::close::status::no_status
static value const no_status
A dummy value to indicate that no status code was received.
Definition: close.hpp:97
websocketpp::close::status::message_too_big
static value const message_too_big
An endpoint received a message too large to process.
Definition: close.hpp:121
websocketpp::close::status::force_tcp_drop
static value const force_tcp_drop
Close the connection with a forced TCP drop.
Definition: close.hpp:72
websocketpp::close::status::terminal
bool terminal(value code)
Determine if the code represents an unrecoverable error.
Definition: close.hpp:217
websocketpp::close::status::internal_endpoint_error
static value const internal_endpoint_error
Definition: close.hpp:133