// Copyright (c) 2005-2007 Hartmut Kaiser (hartmut.kaiser@gmail.com) // // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////// namespace saga { namespace impl { ///////////////////////////////////////////////////////////////////////////// // // utility calls // namespace { inline bool is_escape_sequence (std::string const & str, std::string::size_type pos) { return (std::string::npos != pos && isxdigit (str[pos + 1]) && isxdigit (str[pos + 2]) ); } inline char unescape_char (std::string const & str, std::string::size_type pos) { using namespace boost::spirit; using namespace phoenix; char result = 0; if ( ! parse (&str.c_str ()[pos], hex_escape_p[phoenix::var (result) = arg1]).hit ) SAGA_THROW_VERBATIM(saga::object(), "invalid url: " + str, saga::IncorrectURL); return result; } inline std::string unescape_lit (std::string const & value) { std::string result; std::string::size_type pos = 0; std::string::size_type pos1 = value.find_first_of ("%", 0); if ( is_escape_sequence (value, pos1) ) { do { result += value.substr (pos, pos1 - pos) + unescape_char (value, pos1 + 1); pos1 = value.find_first_of ("%", pos = pos1 + 3); } while ( is_escape_sequence (value, pos1) ); result += value.substr (pos); } else { result = value; } return result; } } // namespace ///////////////////////////////////////////////////////////////////////////// // // URL method implementations // url::url (std::string const & urlstr) : port_(-1) { if (!urlstr.empty()) { boost::recursive_mutex::scoped_lock lock (mtx_); check (urlstr); } } url::url (url const & rhs) : scheme_ (rhs.scheme_), scheme_specific_part_(rhs.scheme_specific_part_), username_ (rhs.username_), password_ (rhs.password_), host_ (rhs.host_), port_ (rhs.port_), fragment_ (rhs.fragment_), path_ (rhs.path_), params_ (rhs.params_), query_ (rhs.query_) { } url::~url (void) { } void url::check (std::string const & urlstr) { reset (); url_grammar g (*this); boost::spirit::parse_info <> pi = boost::spirit::parse (urlstr.c_str (), g); if ( ! pi.full ) SAGA_THROW("invalid url (could not parse): " + urlstr, saga::IncorrectURL); // invalid url, if username or port are given but no host if ( host_.empty() && (-1 != port_ || ! username_.empty () || !password_.empty()) ) SAGA_THROW("invalid url (no host): " + urlstr, saga::IncorrectURL); // invalid url: invalid character in host if ( ! host_.empty () && std::string::npos != host_.find_first_of ("/") ) SAGA_THROW("invalid url (invalid host character): " + urlstr, saga::IncorrectURL); } void url::reset (void) { port_ = -1; scheme_.clear (); scheme_specific_part_.clear(); username_.clear (); password_.clear (); host_.clear (); fragment_.clear (); path_.clear (); params_.clear (); query_.clear (); } std::string url::get_url (void) const { boost::recursive_mutex::scoped_lock lock (mtx_); std::string result (scheme_); if ( ! result.empty () ) { result += ':'; } std::string authority (get_authority ()); if ( ! authority.empty () ) { result += "//"; result += authority; result += '/'; } if ( ! path_.empty () ) { result += path_; } if ( ! query_.empty () ) { result += '?'; result += query_; } if ( ! fragment_.empty () ) { result += '#'; result += fragment_; } return result; } std::string const & url::get_scheme (void) const { boost::recursive_mutex::scoped_lock lock (mtx_); return scheme_; } std::string const & url::get_host (void) const { boost::recursive_mutex::scoped_lock lock (mtx_); return host_; } int url::get_port (void) const { boost::recursive_mutex::scoped_lock lock (mtx_); return port_; } std::string url::get_authority (void) const { boost::recursive_mutex::scoped_lock lock (mtx_); SAGA_OSSTREAM strm; std::string userinfo(get_userinfo()); strm << userinfo; if ( ! get_host ().empty () ) { if ( ! userinfo.empty () ) strm << '@'; strm << get_host (); } if ( -1 != get_port () ) { if ( ! userinfo.empty () || ! get_host ().empty () ) strm << ':'; strm << get_port (); } return SAGA_OSSTREAM_GETSTRING (strm); } std::string const& url::get_fragment (void) const { boost::recursive_mutex::scoped_lock lock (mtx_); return fragment_; } std::string const& url::get_path (void) const { boost::recursive_mutex::scoped_lock lock (mtx_); return path_; } std::string const& url::get_query (void) const { boost::recursive_mutex::scoped_lock lock (mtx_); return query_; } std::string url::get_userinfo (void) const { boost::recursive_mutex::scoped_lock lock (mtx_); std::string result (username_); if (!password_.empty()) result += ":" + password_; return result; } std::string const& url::get_username (void) const { boost::recursive_mutex::scoped_lock lock (mtx_); return username_; } std::string const& url::get_password (void) const { boost::recursive_mutex::scoped_lock lock (mtx_); return password_; } /////////////////////////////////////////////////////////////////////////////// void url::set_scheme (std::string const & scheme) { boost::recursive_mutex::scoped_lock lock (mtx_); scheme_ = unescape_lit (scheme.substr (0, scheme.find_first_of (':'))); boost::to_lower (scheme_); } void url::set_scheme_specific_part (std::string const & scheme_specific_part) { boost::recursive_mutex::scoped_lock lock (mtx_); scheme_specific_part_ = unescape_lit (scheme_specific_part); } void url::set_host_userinfo (std::string const & host, std::string const & userinfo) { boost::recursive_mutex::scoped_lock lock (mtx_); host_ = unescape_lit (host); boost::to_lower (host_); std::string ui (unescape_lit (userinfo)); std::string::size_type p1 = ui.find_first_of (':'); std::string::size_type p2 = ui.find_first_of ('@'); if (p1 != std::string::npos) { username_ = unescape_lit (ui.substr (0, p1)); password_ = ui.substr(p1+1, p2-p1-1); } else { username_ = unescape_lit (ui.substr (0, p2)); } } void url::set_port (int port) { boost::recursive_mutex::scoped_lock lock (mtx_); port_ = port; } void url::set_fragment (std::string const & fragment) { boost::recursive_mutex::scoped_lock lock (mtx_); fragment_ = unescape_lit (fragment); } void url::set_path (std::string const & path) { boost::recursive_mutex::scoped_lock lock (mtx_); path_ = unescape_lit (path); } void url::set_query (std::string const & query) { boost::recursive_mutex::scoped_lock lock (mtx_); query_ = unescape_lit (query); } void url::set_params (std::string const & params) { boost::recursive_mutex::scoped_lock lock (mtx_); params_ = unescape_lit (params); } /////////////////////////////////////////////////////////////////////////////// void url::change_scheme (std::string const & scheme) { boost::recursive_mutex::scoped_lock lock (mtx_); scheme_ = scheme; check (get_url ()); // throws on error } void url::change_scheme_specific_part (std::string const & scheme_specific_part) { boost::recursive_mutex::scoped_lock lock (mtx_); scheme_specific_part_ = scheme_specific_part; check (get_url ()); // throws on error } void url::change_host (std::string const & host) { boost::recursive_mutex::scoped_lock lock (mtx_); host_ = host; check (get_url ()); // throws on error } void url::change_port (int port) { boost::recursive_mutex::scoped_lock lock (mtx_); port_ = port; check (get_url ()); // throws on error } void url::change_fragment (std::string const & fragment) { boost::recursive_mutex::scoped_lock lock (mtx_); fragment_ = fragment; check (get_url ()); // throws on error } void url::change_path (std::string const & newpath) { boost::recursive_mutex::scoped_lock lock (mtx_); path_ = newpath; check (get_url ()); // throws on error } void url::change_query (std::string const & query) { boost::recursive_mutex::scoped_lock lock (mtx_); query_ = query; check (get_url ()); // throws on error } void url::change_userinfo (std::string const & userinfo) { boost::recursive_mutex::scoped_lock lock (mtx_); std::string::size_type p1 = userinfo.find_first_of (':'); std::string::size_type p2 = userinfo.find_first_of ('@'); if (p1 != std::string::npos) { username_ = unescape_lit (userinfo.substr (0, p1)); password_ = userinfo.substr(p1+1, p2-p1-1); } else { username_ = unescape_lit (userinfo.substr (0, p2)); password_.clear(); } check (get_url ()); // throws on error } void url::change_username (std::string const & username) { boost::recursive_mutex::scoped_lock lock (mtx_); username_ = username; check (get_url ()); // throws on error } void url::change_password (std::string const & password) { boost::recursive_mutex::scoped_lock lock (mtx_); password_ = password; check (get_url ()); // throws on error } } } // namespace saga::impl ///////////////////////////////////////////////////////////////////////////////