From 02de3ebcdce2d8a34cce2cdc6188b2a4b37421bb Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Tue, 8 Nov 2011 08:27:00 -0600 Subject: [PATCH] sketches out some of the new interfaces --- src/interfaces/connection_handler.hpp | 104 ++++++++++++++++++++ src/interfaces/frame_parser.hpp | 135 ++++++++++++++++++++++++++ src/interfaces/protocol.hpp | 60 ++++++++++++ src/interfaces/session.hpp | 48 +++++++++ websocketpp.xcodeproj/project.pbxproj | 16 +++ 5 files changed, 363 insertions(+) create mode 100644 src/interfaces/connection_handler.hpp create mode 100644 src/interfaces/frame_parser.hpp create mode 100644 src/interfaces/protocol.hpp create mode 100644 src/interfaces/session.hpp diff --git a/src/interfaces/connection_handler.hpp b/src/interfaces/connection_handler.hpp new file mode 100644 index 0000000000..7fbff6cb35 --- /dev/null +++ b/src/interfaces/connection_handler.hpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011, 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 WEBSOCKET_INTERFACE_CONNECTION_HANDLER_HPP +#define WEBSOCKET_INTERFACE_CONNECTION_HANDLER_HPP + +#include + +#include +#include + +namespace websocketpp { + +class connection_handler { +public: + // validate will be called after a websocket handshake has been received and + // before it is accepted. It provides a handler the ability to refuse a + // connection based on application specific logic (ex: restrict domains or + // negotiate subprotocols). To reject the connection throw a handshake_error + // + // Validate is never called for client sessions. To refuse a client session + // (ex: if you do not like the set of extensions/subprotocols the server + // chose) you can close the connection immediately in the on_open method. + // + // handshake_error parameters: + // log_message - error message to send to server log + // http_error_code - numeric HTTP error code to return to the client + // http_error_msg - (optional) string HTTP error code to return to the + // client (useful for returning non-standard error codes) + virtual void validate(session_ptr session) {}; + + // on_open is called after the websocket session has been successfully + // established and is in the OPEN state. The session is now avaliable to + // send messages and will begin reading frames and calling the on_message/ + // on_close/on_error callbacks. A client may reject the connection by + // closing the session at this point. + virtual void on_open(session_ptr session) = 0; + + // on_close is called whenever an open session is closed for any reason. + // This can be due to either endpoint requesting a connection close or an + // error occuring. Information about why the session was closed can be + // extracted from the session itself. + // + // on_close will be the last time a session calls its handler. If your + // application will need information from `session` after this function you + // should either save the session_ptr somewhere or copy the data out. + virtual void on_close(session_ptr session) = 0; + + // on_message (binary version) will be called when a binary message is + // recieved. Message data is passed as a vector of bytes (unsigned char). + // data will not be avaliable after this callback ends so the handler must + // either completely process the message or copy it somewhere else for + // processing later. + virtual void on_message(session_ptr session, + const std::vector &data) = 0; + + // on_message (text version). Identical to on_message except the data + // parameter is a string interpreted as UTF-8. WebSocket++ guarantees that + // this string is valid UTF-8. + virtual void on_message(session_ptr session,const std::string &msg) = 0; + + + + // #### optional error cases #### + + // on_fail is called whenever a session is terminated or failed before it + // was successfully established. This happens if there is an error during + // the handshake process or if the server refused the connection. + // + // on_fail will be the last time a session calls its handler. If your + // application will need information from `session` after this function you + // should either save the session_ptr somewhere or copy the data out. + virtual void on_fail(session_ptr session) {}; + + // experimental + virtual void on_ping_timeout(session_ptr session) {} +}; + +} +#endif // WEBSOCKET_INTERFACE_CONNECTION_HANDLER_HPP diff --git a/src/interfaces/frame_parser.hpp b/src/interfaces/frame_parser.hpp new file mode 100644 index 0000000000..68f5bf86f1 --- /dev/null +++ b/src/interfaces/frame_parser.hpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2011, 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 WEBSOCKET_INTERFACE_FRAME_PARSER_HPP +#define WEBSOCKET_INTERFACE_FRAME_PARSER_HPP + +#include +#include +#include + +namespace websocketpp { +namespace frame { + +namespace error { + enum value { + FATAL_SESSION_ERROR = 0, // force session end + SOFT_SESSION_ERROR = 1, // should log and ignore + PROTOCOL_VIOLATION = 2, // must end session + PAYLOAD_VIOLATION = 3, // should end session + INTERNAL_SERVER_ERROR = 4, // cleanly end session + MESSAGE_TOO_BIG = 5 // ??? + }; +} + +// Opcodes are 4 bits +// See spec section 5.2 +namespace opcode { + enum value { + CONTINUATION = 0x0, + TEXT = 0x1, + BINARY = 0x2, + RSV3 = 0x3, + RSV4 = 0x4, + RSV5 = 0x5, + RSV6 = 0x6, + RSV7 = 0x7, + CLOSE = 0x8, + PING = 0x9, + PONG = 0xA, + CONTROL_RSVB = 0xB, + CONTROL_RSVC = 0xC, + CONTROL_RSVD = 0xD, + CONTROL_RSVE = 0xE, + CONTROL_RSVF = 0xF, + }; + + inline bool reserved(value v) { + return (v >= RSV3 && v <= RSV7) || + (v >= CONTROL_RSVB && v <= CONTROL_RSVF); + } + + inline bool invalid(value v) { + return (v > 0xF || v < 0); + } + + inline bool is_control(value v) { + return v >= 0x8; + } +} + +namespace limits { + static const uint8_t PAYLOAD_SIZE_BASIC = 125; + static const uint16_t PAYLOAD_SIZE_EXTENDED = 0xFFFF; // 2^16, 65535 + static const uint64_t PAYLOAD_SIZE_JUMBO = 0x7FFFFFFFFFFFFFFF;//2^63 + + // hardcoded limit + static const uint64_t INTERNAL_MAX_PAYLOAD_SIZE = 100000000; // 100MB +} + +class exception : public std::exception { +public: + exception(const std::string& msg, + frame::error::value code = frame::error::FATAL_SESSION_ERROR) + : m_msg(msg),m_code(code) {} + ~exception() throw() {} + + virtual const char* what() const throw() { + return m_msg.c_str(); + } + + frame::error::value code() const throw() { + return m_code; + } + + std::string m_msg; + frame::error::value m_code; +}; + +class interface { +public: + // consume + virtual bool ready() const = 0; + virtual bool uint64_t get_bytes_needed() const = 0; + virtual void reset() = 0; + + virtual void consume(std::istream& s) = 0; + + // retrieve buffers + + // read frame options + + // Is the last fragment in a message sequence? + virtual bool get_fin() const = 0; + virtual opcode::value() const = 0; + +}; + + +} +} +#endif // WEBSOCKET_INTERFACE_FRAME_PARSER_HPP diff --git a/src/interfaces/protocol.hpp b/src/interfaces/protocol.hpp new file mode 100644 index 0000000000..aa25c0ecdc --- /dev/null +++ b/src/interfaces/protocol.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, 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 WEBSOCKET_INTERFACE_FRAME_PARSER_HPP +#define WEBSOCKET_INTERFACE_FRAME_PARSER_HPP + +namespace websocketpp { +namespace protocol { + +class protocol { + // validate client handshake + // validate server handshake + + // Given a list of HTTP headers determine if the values are sufficient + // to start a websocket session. If so begin constructing a response, if not throw a handshake + // exception. + // validate handshake request + + + + // Given a list of HTTP headers determin if the values are a reasonable + // response to our handshake request. If so + + // construct + + + // consume + // is_message_complete + // deliver message (get_payload) + // some sort of message type? for onping onpong? +}; + + +} +} +#endif // WEBSOCKET_INTERFACE_FRAME_PARSER_HPP diff --git a/src/interfaces/session.hpp b/src/interfaces/session.hpp new file mode 100644 index 0000000000..e96d4f0686 --- /dev/null +++ b/src/interfaces/session.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011, 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 WEBSOCKET_INTERFACE_SESSION_HPP +#define WEBSOCKET_INTERFACE_SESSION_HPP + +namespace websocketpp { +namespace session { + + +// +class interface { +public: + // Valid always + //virtual ??? get_state() const = 0; + + // Valid for CONNECTING connections + +}; + + +} +} +#endif // WEBSOCKET_INTERFACE_SESSION_HPP diff --git a/websocketpp.xcodeproj/project.pbxproj b/websocketpp.xcodeproj/project.pbxproj index b0085b938c..95e65ad750 100644 --- a/websocketpp.xcodeproj/project.pbxproj +++ b/websocketpp.xcodeproj/project.pbxproj @@ -141,6 +141,10 @@ B61387A6145D849E00ED9B19 /* parser.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = parser.hpp; path = src/http/parser.hpp; sourceTree = ""; }; B61387B31462AD4900ED9B19 /* session_handler_interface.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = session_handler_interface.hpp; path = src/session_handler_interface.hpp; sourceTree = ""; }; B61387B61462B35700ED9B19 /* logger.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = logger.hpp; path = src/logger/logger.hpp; sourceTree = ""; }; + B62A5A3114695185005F9EB0 /* connection_handler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = connection_handler.hpp; path = src/interfaces/connection_handler.hpp; sourceTree = ""; }; + B62A5A3214695185005F9EB0 /* frame_parser.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = frame_parser.hpp; path = src/interfaces/frame_parser.hpp; sourceTree = ""; }; + B62A5A3314695185005F9EB0 /* session.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = session.hpp; path = src/interfaces/session.hpp; sourceTree = ""; }; + B62A5A34146963FE005F9EB0 /* protocol.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = protocol.hpp; path = src/interfaces/protocol.hpp; sourceTree = ""; }; B6828875143745DA002BA48B /* chat_client_handler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = chat_client_handler.cpp; path = examples/chat_client/chat_client_handler.cpp; sourceTree = ""; }; B6828876143745DA002BA48B /* chat_client_handler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = chat_client_handler.hpp; path = examples/chat_client/chat_client_handler.hpp; sourceTree = ""; }; B6828877143745DA002BA48B /* chat_client.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = chat_client.cpp; path = examples/chat_client/chat_client.cpp; sourceTree = ""; }; @@ -266,6 +270,17 @@ name = logger; sourceTree = ""; }; + B62A5A2F1469512A005F9EB0 /* interfaces */ = { + isa = PBXGroup; + children = ( + B62A5A3114695185005F9EB0 /* connection_handler.hpp */, + B62A5A3214695185005F9EB0 /* frame_parser.hpp */, + B62A5A3314695185005F9EB0 /* session.hpp */, + B62A5A34146963FE005F9EB0 /* protocol.hpp */, + ); + name = interfaces; + sourceTree = ""; + }; B6CF18121437C370009295BE /* echo_client */ = { isa = PBXGroup; children = ( @@ -311,6 +326,7 @@ B6DF1C7F1434ABB70029A1B1 /* src */ = { isa = PBXGroup; children = ( + B62A5A2F1469512A005F9EB0 /* interfaces */, B6FE8D1414686A6D00B32547 /* md5 */, B61387B51462B34400ED9B19 /* logger */, B61387A4145D847A00ED9B19 /* http */,