diff --git a/include/frnetlib/URL.h b/include/frnetlib/URL.h index 0f7d69e..9c833ed 100644 --- a/include/frnetlib/URL.h +++ b/include/frnetlib/URL.h @@ -8,116 +8,118 @@ #include //Note, a URL looks like this: scheme:[//host[:port]][/path][?query][#fragment] - -class URL +namespace fr { -public: - enum Scheme + class URL { - HTTP = 0, - HTTPS = 1, - FTP = 2, - MAILTO = 3, - IRC = 4, - SFTP = 5, - Unknown = 6, + public: + enum Scheme + { + HTTP = 0, + HTTPS = 1, + FTP = 2, + MAILTO = 3, + IRC = 4, + SFTP = 5, + Unknown = 6, + }; + + /*! + * Constructors + */ + URL() = default; + + URL(const std::string &url); + + /*! + * Parses a given URL, extracting its various components + * + * @param url The URL to parse + */ + void parse(std::string url); + + /*! + * Get the URL scheme + */ + inline Scheme get_scheme() + { + return scheme; + } + + /* + * Get the URL host + */ + inline const std::string &get_host() + { + return host; + } + + /* + * Get the URL port + */ + inline const std::string &get_port() + { + return port; + } + + /* + * Get the URL path + */ + inline const std::string &get_path() + { + return path; + } + + /* + * Get the URL query + */ + inline const std::string &get_query() + { + return query; + } + + /* + * Get the URL fragment + */ + inline const std::string &get_fragment() + { + return fragment; + } + + /*! + * Converts a string to a scheme enum. + * + * @param scheme The string scheme to convert + * @return The associated scheme enum value. Scheme::Unknown on failure. + */ + static Scheme string_to_scheme(const std::string &scheme); + + /*! + * Converts a scheme enum value to a string + * + * @param scheme The scheme value to convert + * @return The string version + */ + static const std::string &scheme_to_string(Scheme scheme); + + private: + /*! + * Converts a string to lower case + * + * @param str The string to convert + * @return The converted string + */ + static std::string to_lower(const std::string &str); + + //State + Scheme scheme; + std::string host; + std::string port; + std::string path; + std::string query; + std::string fragment; + static std::unordered_map scheme_string_map; }; - - /*! - * Constructors - */ - URL() = default; - URL(const std::string &url); - - /*! - * Parses a given URL, extracting its various components - * - * @param url The URL to parse - */ - void parse(std::string url); - - /*! - * Get the URL scheme - */ - inline Scheme get_scheme() - { - return scheme; - } - - /* - * Get the URL host - */ - inline const std::string &get_host() - { - return host; - } - - /* - * Get the URL port - */ - inline const std::string &get_port() - { - return port; - } - - /* - * Get the URL path - */ - inline const std::string &get_path() - { - return path; - } - - /* - * Get the URL query - */ - inline const std::string &get_query() - { - return query; - } - - /* - * Get the URL fragment - */ - inline const std::string &get_fragment() - { - return fragment; - } - - /*! - * Converts a string to a scheme enum. - * - * @param scheme The string scheme to convert - * @return The associated scheme enum value. Scheme::Unknown on failure. - */ - static Scheme string_to_scheme(const std::string &scheme); - - /*! - * Converts a scheme enum value to a string - * - * @param scheme The scheme value to convert - * @return The string version - */ - static const std::string &scheme_to_string(Scheme scheme); - -private: - /*! - * Converts a string to lower case - * - * @param str The string to convert - * @return The converted string - */ - static std::string to_lower(const std::string &str); - - //State - Scheme scheme; - std::string host; - std::string port; - std::string path; - std::string query; - std::string fragment; - static std::unordered_map scheme_string_map; -}; - +} #endif //FRNETLIB_URLPARSER_H diff --git a/src/URL.cpp b/src/URL.cpp index cafc0d2..efc18ea 100644 --- a/src/URL.cpp +++ b/src/URL.cpp @@ -7,121 +7,126 @@ #include #include "frnetlib/URL.h" -std::unordered_map URL::scheme_string_map = { - {"http", URL::HTTP}, - {"https", URL::HTTPS}, - {"sftp", URL::FTP}, - {"mailto", URL::MAILTO}, - {"irc", URL::IRC}, - {"sftp", URL::SFTP}, - {"unknown", URL::Unknown} -}; - -URL::URL(const std::string &url) +namespace fr { - parse(url); -} + std::unordered_map URL::scheme_string_map = { + {"http", URL::HTTP}, + {"https", URL::HTTPS}, + {"sftp", URL::FTP}, + {"mailto", URL::MAILTO}, + {"irc", URL::IRC}, + {"sftp", URL::SFTP}, + {"unknown", URL::Unknown} + }; -void URL::parse(std::string url) -{ - size_t parse_offset = 0; - size_t pos = 0; - - //Check to see if a scheme exists - pos = url.find("://"); - if(pos != std::string::npos) + URL::URL(const std::string &url) { - auto scheme_pos = scheme_string_map.find(to_lower(url.substr(0, pos))); - scheme = (scheme_pos == scheme_string_map.end()) ? URL::Unknown : scheme_pos->second; - parse_offset = pos + 3; + parse(url); } - //Check to see if there's a port - pos = url.find(":", parse_offset); - if(pos != std::string::npos) - { - //Store host - host = url.substr(parse_offset, pos - parse_offset); - parse_offset += host.size(); - //Find end of port - size_t port_end = url.find("/", parse_offset); - port_end = (port_end == std::string::npos) ? url.size() : port_end; - port = url.substr(pos + 1, port_end - pos - 1); - parse_offset = port_end + 1; - } - else + void URL::parse(std::string url) { - //Store host - pos = url.find("/", parse_offset); - pos = (pos != std::string::npos) ? pos : url.find("?", parse_offset); - pos = (pos != std::string::npos) ? pos : url.find("#", parse_offset); - pos = (pos != std::string::npos) ? pos : url.size(); - host = url.substr(parse_offset, pos - parse_offset); - parse_offset = pos + 1; - } + size_t parse_offset = 0; + size_t pos = 0; - //Exit if done - if(parse_offset >= url.size()) - return; + //Check to see if a scheme exists + pos = url.find("://"); + if(pos != std::string::npos) + { + auto scheme_pos = scheme_string_map.find(to_lower(url.substr(0, pos))); + scheme = (scheme_pos == scheme_string_map.end()) ? URL::Unknown : scheme_pos->second; + parse_offset = pos + 3; + } - //Extract the path - pos = url.find("?", parse_offset); - if(pos != std::string::npos) - { - path = url.substr(parse_offset, pos - parse_offset); - parse_offset = pos + 1; - } - else - { - pos = url.find("#", parse_offset); - pos = (pos != std::string::npos) ? pos : url.find("?", parse_offset); - pos = (pos != std::string::npos) ? pos : url.size(); - path = url.substr(parse_offset, pos - parse_offset); - parse_offset = pos + 1; - } + //Check to see if there's a port + pos = url.find(":", parse_offset); + if(pos != std::string::npos) + { + //Store host + host = url.substr(parse_offset, pos - parse_offset); + parse_offset += host.size(); - //Extract the query - pos = url.find("#", parse_offset - 1); - if(pos != std::string::npos) - { - if(pos + 1 != parse_offset) - query = url.substr(parse_offset, pos - parse_offset); - fragment = url.substr(pos + 1, url.size() - pos - 1); - } - else - { + //Find end of port + size_t port_end = url.find("/", parse_offset); + port_end = (port_end == std::string::npos) ? url.size() : port_end; + port = url.substr(pos + 1, port_end - pos - 1); + parse_offset = port_end + 1; + } + else + { + //Store host + pos = url.find("/", parse_offset); + pos = (pos != std::string::npos) ? pos : url.find("?", parse_offset); + pos = (pos != std::string::npos) ? pos : url.find("#", parse_offset); + pos = (pos != std::string::npos) ? pos : url.size(); + host = url.substr(parse_offset, pos - parse_offset); + parse_offset = pos + 1; + } + + //Exit if done if(parse_offset >= url.size()) return; - query = url.substr(parse_offset, url.size() - parse_offset); + + //Extract the path + pos = url.find("?", parse_offset); + if(pos != std::string::npos) + { + path = url.substr(parse_offset, pos - parse_offset); + parse_offset = pos + 1; + } + else + { + pos = url.find("#", parse_offset); + pos = (pos != std::string::npos) ? pos : url.find("?", parse_offset); + pos = (pos != std::string::npos) ? pos : url.size(); + path = url.substr(parse_offset, pos - parse_offset); + parse_offset = pos + 1; + } + + //Extract the query + pos = url.find("#", parse_offset - 1); + if(pos != std::string::npos) + { + if(pos + 1 != parse_offset) + query = url.substr(parse_offset, pos - parse_offset); + fragment = url.substr(pos + 1, url.size() - pos - 1); + } + else + { + if(parse_offset >= url.size()) + return; + query = url.substr(parse_offset, url.size() - parse_offset); + } + + return; } - return; -} + URL::Scheme URL::string_to_scheme(const std::string &scheme) + { + auto iter = scheme_string_map.find(to_lower(scheme)); + if(iter == scheme_string_map.end()) + return URL::Unknown; + return iter->second; + } -URL::Scheme URL::string_to_scheme(const std::string &scheme) -{ - auto iter = scheme_string_map.find(to_lower(scheme)); - if(iter == scheme_string_map.end()) - return URL::Unknown; - return iter->second; -} + std::string URL::to_lower(const std::string &str) + { + std::string out = str; + std::transform(out.begin(), out.end(), out.begin(), ::tolower); + return out; + } -std::string URL::to_lower(const std::string &str) -{ - std::string out = str; - std::transform(out.begin(), out.end(), out.begin(), ::tolower); - return out; -} + const std::string &URL::scheme_to_string(URL::Scheme scheme) + { + auto iter = std::find_if(scheme_string_map.begin(), scheme_string_map.end(), [&](const auto &i) + { + return i.second == scheme; + }); -const std::string &URL::scheme_to_string(URL::Scheme scheme) -{ - auto iter = std::find_if(scheme_string_map.begin(), scheme_string_map.end(), [&](const auto &i){ - return i.second == scheme; - }); - - if(iter == scheme_string_map.end()) - throw std::logic_error("Unknown URL::Scheme value " + std::to_string(scheme)); - return iter->first; -} + if(iter == scheme_string_map.end()) + throw std::logic_error("Unknown URL::Scheme value " + std::to_string(scheme)); + return iter->first; + } +} \ No newline at end of file