diff options
author | Luca Muscariello <lumuscar+fdio@cisco.com> | 2017-02-25 23:42:31 +0100 |
---|---|---|
committer | Luca Muscariello <lumuscar+fdio@cisco.com> | 2017-02-25 23:42:31 +0100 |
commit | 05c1a838c881ea502888659848d8792843b28718 (patch) | |
tree | cf0b05b58bd725a1eb6c80325ba986c63dea42aa /websocketpp/close.hpp | |
parent | 9b30fc10fb1cbebe651e5a107e8ca5b24de54675 (diff) |
Initial commit: video player - viper
Change-Id: Id5aa33598ce34659bad4a7a9ae5006bfb84f9bd1
Signed-off-by: Luca Muscariello <lumuscar+fdio@cisco.com>
Diffstat (limited to 'websocketpp/close.hpp')
-rw-r--r-- | websocketpp/close.hpp | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/websocketpp/close.hpp b/websocketpp/close.hpp new file mode 100644 index 00000000..ded77657 --- /dev/null +++ b/websocketpp/close.hpp @@ -0,0 +1,342 @@ + +/* + * Copyright (c) 2014, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WEBSOCKETPP_CLOSE_HPP +#define WEBSOCKETPP_CLOSE_HPP + +/** \file + * A package of types and methods for manipulating WebSocket close codes. + */ + +#include <websocketpp/error.hpp> +#include <websocketpp/common/network.hpp> +#include <websocketpp/common/stdint.hpp> +#include <websocketpp/utf8_validator.hpp> + +#include <string> + +namespace websocketpp { +/// A package of types and methods for manipulating WebSocket close codes. +namespace close { +/// A package of types and methods for manipulating WebSocket close status' +namespace status { + /// The type of a close code value. + typedef uint16_t value; + + /// A blank value for internal use. + static value const blank = 0; + + /// Close the connection without a WebSocket close handshake. + /** + * This special value requests that the WebSocket connection be closed + * without performing the WebSocket closing handshake. This does not comply + * with RFC6455, but should be safe to do if necessary. This could be useful + * for clients that need to disconnect quickly and cannot afford the + * complete handshake. + */ + static value const omit_handshake = 1; + + /// Close the connection with a forced TCP drop. + /** + * This special value requests that the WebSocket connection be closed by + * forcibly dropping the TCP connection. This will leave the other side of + * the connection with a broken connection and some expensive timeouts. this + * should not be done except in extreme cases or in cases of malicious + * remote endpoints. + */ + static value const force_tcp_drop = 2; + + /// Normal closure, meaning that the purpose for which the connection was + /// established has been fulfilled. + static value const normal = 1000; + + /// The endpoint was "going away", such as a server going down or a browser + /// navigating away from a page. + static value const going_away = 1001; + + /// A protocol error occurred. + static value const protocol_error = 1002; + + /// The connection was terminated because an endpoint received a type of + /// data it cannot accept. + /** + * (e.g., an endpoint that understands only text data MAY send this if it + * receives a binary message). + */ + static value const unsupported_data = 1003; + + /// A dummy value to indicate that no status code was received. + /** + * This value is illegal on the wire. + */ + static value const no_status = 1005; + + /// A dummy value to indicate that the connection was closed abnormally. + /** + * In such a case there was no close frame to extract a value from. This + * value is illegal on the wire. + */ + static value const abnormal_close = 1006; + + /// An endpoint received message data inconsistent with its type. + /** + * For example: Invalid UTF8 bytes in a text message. + */ + static value const invalid_payload = 1007; + + /// An endpoint received a message that violated its policy. + /** + * This is a generic status code that can be returned when there is no other + * more suitable status code (e.g., 1003 or 1009) or if there is a need to + * hide specific details about the policy. + */ + static value const policy_violation = 1008; + + /// An endpoint received a message too large to process. + static value const message_too_big = 1009; + + /// A client expected the server to accept a required extension request + /** + * The list of extensions that are needed SHOULD appear in the /reason/ part + * of the Close frame. Note that this status code is not used by the server, + * because it can fail the WebSocket handshake instead. + */ + static value const extension_required = 1010; + + /// An endpoint encountered an unexpected condition that prevented it from + /// fulfilling the request. + static value const internal_endpoint_error = 1011; + + /// Indicates that the service is restarted. A client may reconnect and if + /// if it chooses to do so, should reconnect using a randomized delay of + /// 5-30s + static value const service_restart = 1012; + + /// Indicates that the service is experiencing overload. A client should + /// only connect to a different IP (when there are multiple for the target) + /// or reconnect to the same IP upon user action. + static value const try_again_later = 1013; + + /// An endpoint failed to perform a TLS handshake + /** + * Designated for use in applications expecting a status code to indicate + * that the connection was closed due to a failure to perform a TLS + * handshake (e.g., the server certificate can't be verified). This value is + * illegal on the wire. + */ + static value const tls_handshake = 1015; + + /// A generic subprotocol error + /** + * Indicates that a subprotocol error occurred. Typically this involves + * receiving a message that is not formatted as a valid message for the + * subprotocol in use. + */ + static value const subprotocol_error = 3000; + + /// A invalid subprotocol data + /** + * Indicates that data was received that violated the specification of the + * subprotocol in use. + */ + static value const invalid_subprotocol_data = 3001; + + /// First value in range reserved for future protocol use + static value const rsv_start = 1016; + /// Last value in range reserved for future protocol use + static value const rsv_end = 2999; + + /// Test whether a close code is in a reserved range + /** + * @param [in] code The code to test + * @return Whether or not code is reserved + */ + inline bool reserved(value code) { + return ((code >= rsv_start && code <= rsv_end) || + code == 1004 || code == 1014); + } + + /// First value in range that is always invalid on the wire + static value const invalid_low = 999; + /// Last value in range that is always invalid on the wire + static value const invalid_high = 5000; + + /// Test whether a close code is invalid on the wire + /** + * @param [in] code The code to test + * @return Whether or not code is invalid on the wire + */ + inline bool invalid(value code) { + return (code <= invalid_low || code >= invalid_high || + code == no_status || code == abnormal_close || + code == tls_handshake); + } + + /// Determine if the code represents an unrecoverable error + /** + * There is a class of errors for which once they are discovered normal + * WebSocket functionality can no longer occur. This function determines + * if a given code is one of these values. This information is used to + * determine if the system has the capability of waiting for a close + * acknowledgement or if it should drop the TCP connection immediately + * after sending its close frame. + * + * @param [in] code The value to test. + * @return True if the code represents an unrecoverable error + */ + inline bool terminal(value code) { + return (code == protocol_error || code == invalid_payload || + code == policy_violation || code == message_too_big || + code == internal_endpoint_error); + } + + /// Return a human readable interpretation of a WebSocket close code + /** + * See https://tools.ietf.org/html/rfc6455#section-7.4 for more details. + * + * @since 0.3.0 + * + * @param [in] code The code to look up. + * @return A human readable interpretation of the code. + */ + inline std::string get_string(value code) { + switch (code) { + case normal: + return "Normal close"; + case going_away: + return "Going away"; + case protocol_error: + return "Protocol error"; + case unsupported_data: + return "Unsupported data"; + case no_status: + return "No status set"; + case abnormal_close: + return "Abnormal close"; + case invalid_payload: + return "Invalid payload"; + case policy_violation: + return "Policy violoation"; + case message_too_big: + return "Message too big"; + case extension_required: + return "Extension required"; + case internal_endpoint_error: + return "Internal endpoint error"; + case tls_handshake: + return "TLS handshake failure"; + case subprotocol_error: + return "Generic subprotocol error"; + case invalid_subprotocol_data: + return "Invalid subprotocol data"; + default: + return "Unknown"; + } + } +} // namespace status + +/// Type used to convert close statuses between integer and wire representations +union code_converter { + uint16_t i; + char c[2]; +}; + +/// Extract a close code value from a close payload +/** + * If there is no close value (ie string is empty) status::no_status is + * returned. If a code couldn't be extracted (usually do to a short or + * otherwise mangled payload) status::protocol_error is returned and the ec + * value is flagged as an error. Note that this case is different than the case + * where protocol error is received over the wire. + * + * If the value is in an invalid or reserved range ec is set accordingly. + * + * @param [in] payload Close frame payload value received over the wire. + * @param [out] ec Set to indicate what error occurred, if any. + * @return The extracted value + */ +inline status::value extract_code(std::string const & payload, lib::error_code + & ec) +{ + ec = lib::error_code(); + + if (payload.size() == 0) { + return status::no_status; + } else if (payload.size() == 1) { + ec = make_error_code(error::bad_close_code); + return status::protocol_error; + } + + code_converter val; + + val.c[0] = payload[0]; + val.c[1] = payload[1]; + + status::value code(ntohs(val.i)); + + if (status::invalid(code)) { + ec = make_error_code(error::invalid_close_code); + } + + if (status::reserved(code)) { + ec = make_error_code(error::reserved_close_code); + } + + return code; +} + +/// Extract the reason string from a close payload +/** + * The string should be a valid UTF8 message. error::invalid_utf8 will be set if + * the function extracts a reason that is not valid UTF8. + * + * @param [in] payload The payload string to extract a reason from. + * @param [out] ec Set to indicate what error occurred, if any. + * @return The reason string. + */ +inline std::string extract_reason(std::string const & payload, lib::error_code + & ec) +{ + std::string reason; + ec = lib::error_code(); + + if (payload.size() > 2) { + reason.append(payload.begin()+2,payload.end()); + } + + if (!websocketpp::utf8_validator::validate(reason)) { + ec = make_error_code(error::invalid_utf8); + } + + return reason; +} + +} // namespace close +} // namespace websocketpp + +#endif // WEBSOCKETPP_CLOSE_HPP |