peerplays-fc/src/network/url.cpp
2019-04-04 17:59:51 +02:00

198 lines
4.9 KiB
C++

#include <fc/network/url.hpp>
#include <fc/io/sstream.hpp>
#include <fc/exception/exception.hpp>
#include <fc/log/logger.hpp>
#include <sstream>
namespace fc
{
namespace detail
{
class url_impl
{
public:
void parse( const std::string& s )
{
std::stringstream ss(s);
std::string skip,_lpath,_largs,luser,lpass;
std::getline( ss, _proto, ':' );
std::getline( ss, skip, '/' );
std::getline( ss, skip, '/' );
if( s.find('@') != size_t(std::string::npos) ) {
std::string user_pass;
std::getline( ss, user_pass, '@' );
std::stringstream upss(user_pass);
if( user_pass.find( ':' ) != size_t(std::string::npos) ) {
std::getline( upss, luser, ':' );
std::getline( upss, lpass, ':' );
_user = std::move(luser);
_pass = std::move(lpass);
} else {
_user = std::move(user_pass);
}
}
std::string host_port;
std::getline( ss, host_port, '/' );
auto pos = host_port.find( ':' );
if( pos != std::string::npos ) {
try {
_port = static_cast<uint16_t>(to_uint64( host_port.substr( pos+1 ) ));
} catch ( ... ) {
FC_THROW_EXCEPTION( parse_error_exception, "Unable to parse port field in url",( "url", s ) );
}
_host = host_port.substr(0,pos);
} else {
_host = std::move(host_port);
}
std::getline( ss, _lpath, '?' );
#ifdef WIN32
// On windows, a URL like file:///c:/autoexec.bat would result in _lpath = c:/autoexec.bat
// which is what we really want (it's already an absolute path)
if (!stricmp(_proto.c_str(), "file"))
_path = _lpath;
else
_path = fc::path( "/" ) / _lpath; // let other schemes behave like unix
#else
// On unix, a URL like file:///etc/rc.local would result in _lpath = etc/rc.local
// but we really want to make it the absolute path /etc/rc.local
_path = fc::path( "/" ) / _lpath;
#endif
std::getline( ss, _largs );
if( _args.valid() && _args->size() )
{
// TODO: args = std::move(_args);
}
}
string _proto;
ostring _host;
ostring _user;
ostring _pass;
opath _path;
ovariant_object _args;
fc::optional<uint16_t> _port;
};
}
void to_variant( const url& u, fc::variant& v, uint32_t max_depth )
{
v = std::string(u);
}
void from_variant( const fc::variant& v, url& u, uint32_t max_depth )
{
u = url( v.as_string() );
}
url::operator string()const
{
std::stringstream ss;
ss<<my->_proto<<"://";
if( my->_user.valid() ) {
ss << *my->_user;
if( my->_pass.valid() ) {
ss<<":"<<*my->_pass;
}
ss<<"@";
}
if( my->_host.valid() ) ss<<*my->_host;
if( my->_port.valid() ) ss<<":"<<*my->_port;
if( my->_path.valid() ) ss<<my->_path->generic_string();
return ss.str();
}
url::url( const std::string& u )
:my( std::make_shared<detail::url_impl>() )
{
my->parse(u);
}
std::shared_ptr<detail::url_impl> get_null_url()
{
static auto u = std::make_shared<detail::url_impl>();
return u;
}
url::url()
:my( get_null_url() )
{ }
url::url( const url& u )
:my(u.my){}
url::url( url&& u )
:my( std::move(u.my) )
{
u.my = get_null_url();
}
url::url( const mutable_url& mu )
:my( std::make_shared<detail::url_impl>(*mu.my) )
{
}
url::url( mutable_url&& mu )
:my( std::move( mu.my ) )
{ }
url::~url(){}
url& url::operator=(const url& u )
{
my = u.my;
return *this;
}
url& url::operator=(url&& u )
{
if( this != &u )
{
my = std::move(u.my);
u.my= get_null_url();
}
return *this;
}
url& url::operator=(const mutable_url& u )
{
my = std::make_shared<detail::url_impl>(*u.my);
return *this;
}
url& url::operator=(mutable_url&& u )
{
my = std::move(u.my);
return *this;
}
string url::proto()const
{
return my->_proto;
}
ostring url::host()const
{
return my->_host;
}
ostring url::user()const
{
return my->_user;
}
ostring url::pass()const
{
return my->_pass;
}
opath url::path()const
{
return my->_path;
}
ovariant_object url::args()const
{
return my->_args;
}
fc::optional<uint16_t> url::port()const
{
return my->_port;
}
}