diff options
Diffstat (limited to 'websocketpp/uri.hpp')
-rw-r--r-- | websocketpp/uri.hpp | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/websocketpp/uri.hpp b/websocketpp/uri.hpp new file mode 100644 index 00000000..7159234f --- /dev/null +++ b/websocketpp/uri.hpp @@ -0,0 +1,355 @@ +/* + * 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_URI_HPP +#define WEBSOCKETPP_URI_HPP + +#include <websocketpp/error.hpp> + +#include <websocketpp/common/memory.hpp> + +#include <algorithm> +#include <sstream> +#include <string> + +namespace websocketpp { + +// TODO: figure out why this fixes horrible linking errors. + +/// Default port for ws:// +static uint16_t const uri_default_port = 80; +/// Default port for wss:// +static uint16_t const uri_default_secure_port = 443; + +class uri { +public: + explicit uri(std::string const & uri_string) : m_valid(false) { + std::string::const_iterator it; + std::string::const_iterator temp; + + int state = 0; + + it = uri_string.begin(); + size_t uri_len = uri_string.length(); + + if (uri_len >= 7 && std::equal(it,it+6,"wss://")) { + m_secure = true; + m_scheme = "wss"; + it += 6; + } else if (uri_len >= 6 && std::equal(it,it+5,"ws://")) { + m_secure = false; + m_scheme = "ws"; + it += 5; + } else if (uri_len >= 8 && std::equal(it,it+7,"http://")) { + m_secure = false; + m_scheme = "http"; + it += 7; + } else if (uri_len >= 9 && std::equal(it,it+8,"https://")) { + m_secure = true; + m_scheme = "https"; + it += 8; + } else { + return; + } + + // extract host. + // either a host string + // an IPv4 address + // or an IPv6 address + if (*it == '[') { + ++it; + // IPv6 literal + // extract IPv6 digits until ] + + // TODO: this doesn't work on g++... not sure why + //temp = std::find(it,it2,']'); + + temp = it; + while (temp != uri_string.end()) { + if (*temp == ']') { + break; + } + ++temp; + } + + if (temp == uri_string.end()) { + return; + } else { + // validate IPv6 literal parts + // can contain numbers, a-f and A-F + m_host.append(it,temp); + } + it = temp+1; + if (it == uri_string.end()) { + state = 2; + } else if (*it == '/') { + state = 2; + ++it; + } else if (*it == ':') { + state = 1; + ++it; + } else { + // problem + return; + } + } else { + // IPv4 or hostname + // extract until : or / + while (state == 0) { + if (it == uri_string.end()) { + state = 2; + break; + } else if (*it == '/') { + state = 2; + } else if (*it == ':') { + // end hostname start port + state = 1; + } else { + m_host += *it; + } + ++it; + } + } + + // parse port + std::string port; + while (state == 1) { + if (it == uri_string.end()) { + // state is not used after this point presently. + // this should be re-enabled if it ever is needed in a future + // refactoring + //state = 3; + break; + } else if (*it == '/') { + state = 3; + } else { + port += *it; + } + ++it; + } + + lib::error_code ec; + m_port = get_port_from_string(port, ec); + + if (ec) { + return; + } + + m_resource = "/"; + m_resource.append(it,uri_string.end()); + + + m_valid = true; + } + + uri(bool secure, std::string const & host, uint16_t port, + std::string const & resource) + : m_scheme(secure ? "wss" : "ws") + , m_host(host) + , m_resource(resource.empty() ? "/" : resource) + , m_port(port) + , m_secure(secure) + , m_valid(true) {} + + uri(bool secure, std::string const & host, std::string const & resource) + : m_scheme(secure ? "wss" : "ws") + , m_host(host) + , m_resource(resource.empty() ? "/" : resource) + , m_port(secure ? uri_default_secure_port : uri_default_port) + , m_secure(secure) + , m_valid(true) {} + + uri(bool secure, std::string const & host, std::string const & port, + std::string const & resource) + : m_scheme(secure ? "wss" : "ws") + , m_host(host) + , m_resource(resource.empty() ? "/" : resource) + , m_secure(secure) + { + lib::error_code ec; + m_port = get_port_from_string(port,ec); + m_valid = !ec; + } + + uri(std::string const & scheme, std::string const & host, uint16_t port, + std::string const & resource) + : m_scheme(scheme) + , m_host(host) + , m_resource(resource.empty() ? "/" : resource) + , m_port(port) + , m_secure(scheme == "wss" || scheme == "https") + , m_valid(true) {} + + uri(std::string scheme, std::string const & host, std::string const & resource) + : m_scheme(scheme) + , m_host(host) + , m_resource(resource.empty() ? "/" : resource) + , m_port((scheme == "wss" || scheme == "https") ? uri_default_secure_port : uri_default_port) + , m_secure(scheme == "wss" || scheme == "https") + , m_valid(true) {} + + uri(std::string const & scheme, std::string const & host, + std::string const & port, std::string const & resource) + : m_scheme(scheme) + , m_host(host) + , m_resource(resource.empty() ? "/" : resource) + , m_secure(scheme == "wss" || scheme == "https") + { + lib::error_code ec; + m_port = get_port_from_string(port,ec); + m_valid = !ec; + } + + bool get_valid() const { + return m_valid; + } + + bool get_secure() const { + return m_secure; + } + + std::string const & get_scheme() const { + return m_scheme; + } + + std::string const & get_host() const { + return m_host; + } + + std::string get_host_port() const { + if (m_port == (m_secure ? uri_default_secure_port : uri_default_port)) { + return m_host; + } else { + std::stringstream p; + p << m_host << ":" << m_port; + return p.str(); + } + } + + std::string get_authority() const { + std::stringstream p; + p << m_host << ":" << m_port; + return p.str(); + } + + uint16_t get_port() const { + return m_port; + } + + std::string get_port_str() const { + std::stringstream p; + p << m_port; + return p.str(); + } + + std::string const & get_resource() const { + return m_resource; + } + + std::string str() const { + std::stringstream s; + + s << m_scheme << "://" << m_host; + + if (m_port != (m_secure ? uri_default_secure_port : uri_default_port)) { + s << ":" << m_port; + } + + s << m_resource; + return s.str(); + } + + /// Return the query portion + /** + * Returns the query portion (after the ?) of the URI or an empty string if + * there is none. + * + * @return query portion of the URI. + */ + std::string get_query() const { + std::size_t found = m_resource.find('?'); + if (found != std::string::npos) { + return m_resource.substr(found + 1); + } else { + return ""; + } + } + + // get fragment + + // hi <3 + + // get the string representation of this URI + + //std::string base() const; // is this still needed? + + // setter methods set some or all (in the case of parse) based on the input. + // These functions throw a uri_exception on failure. + /*void set_uri(const std::string& uri); + + void set_secure(bool secure); + void set_host(const std::string& host); + void set_port(uint16_t port); + void set_port(const std::string& port); + void set_resource(const std::string& resource);*/ +private: + uint16_t get_port_from_string(std::string const & port, lib::error_code & + ec) const + { + ec = lib::error_code(); + + if (port.empty()) { + return (m_secure ? uri_default_secure_port : uri_default_port); + } + + unsigned int t_port = static_cast<unsigned int>(atoi(port.c_str())); + + if (t_port > 65535) { + ec = error::make_error_code(error::invalid_port); + } + + if (t_port == 0) { + ec = error::make_error_code(error::invalid_port); + } + + return static_cast<uint16_t>(t_port); + } + + std::string m_scheme; + std::string m_host; + std::string m_resource; + uint16_t m_port; + bool m_secure; + bool m_valid; +}; + +/// Pointer to a URI +typedef lib::shared_ptr<uri> uri_ptr; + +} // namespace websocketpp + +#endif // WEBSOCKETPP_URI_HPP |