123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- /*
- * 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;
- /// Indicates that the server was acting as a gateway or proxy and received
- /// an invalid response from the upstream server. This is similar to 502
- /// HTTP Status Code.
- static value const bad_gateway = 1014;
- /// 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);
- }
- /// 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 service_restart:
- return "Service restart";
- case try_again_later:
- return "Try again later";
- case bad_gateway:
- return "Bad gateway";
- 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
|