/* * Copyright (C) 2007-2019 Xagasoft, All rights reserved. * * This file is part of the libbu++ library and is released under the * terms of the license contained in the file LICENSE. */ #include "bu/url.h" #ifndef WIN32 # include # include #endif #include char Bu::Url::hexcode[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; Bu::Url::Url() { } Bu::Url::Url( const Bu::String &sUrl ) { parseUrl( sUrl ); } Bu::Url::~Url() { } void Bu::Url::parseUrl( const Bu::String &sUrl ) { clear(); Bu::String::const_iterator i = sUrl.begin(); parseProtocol( i ); parseUserPass( i ); parseHost( i ); parsePath( i ); } Bu::String Bu::Url::decode( const Bu::String &sStr ) { Bu::String sRet; char buf[3] = {0, 0, 0}; for( Bu::String::const_iterator i = sStr.begin(); i; i++ ) { if( *i == '+' ) { sRet += ' '; } else if( *i == '%' ) { i++; buf[0] = *i; i++; buf[1] = *i; sRet += (char)((unsigned char)strtol( buf, NULL, 16 )); } else { sRet += *i; } } return sRet; } Bu::String Bu::Url::encode( const Bu::String &sStr ) { Bu::String sRet; for( Bu::String::const_iterator i = sStr.begin(); i; i++ ) { if( *i == ' ' ) { sRet += '+'; } else if( (*i >= 'A' && *i <= 'Z') || (*i >= 'a' && *i <= 'z') || (*i >= '0' && *i <= '9') || (*i == '-' || *i == '_' || *i == '.' || *i == '~') ) { sRet += *i; } else { unsigned char b = *i; sRet += '%'; sRet += hexcode[(b>>4)&0xF]; sRet += hexcode[b&0xF]; } } return sRet; } void Bu::Url::parseProtocol( Bu::String::const_iterator &i ) { Bu::String::const_iterator s = i.find("://", 3); if( !s ) throw Bu::ExceptionBase("No :// in url"); Bu::String sTmp( i, s ); setProtocol( sTmp ); i = s + 3; } void Bu::Url::setProtocol( const Bu::String &sNewProto, bool bAutoSetPort ) { sProtocol = sNewProto; #ifndef WIN32 if( bAutoSetPort ) { struct servent *se = getservbyname( sProtocol.getStr(), "tcp" ); if( se ) { iPort = ntohs( se->s_port ); } } #endif } void Bu::Url::parseUserPass( Bu::String::const_iterator &i ) { Bu::String::const_iterator s; for( s = i; s && *s != '/' && *s != '@'; s++ ) { } if( !s || *s == '/') return; Bu::String::const_iterator p; for( p = i.find(':'); p && *p != '/' && *p != ':'; p++ ) { } if( p && *p == ':' ) { sUser.set( i, p ); sPass.set( p+1, s ); } else { sUser.set( i, s ); } i = s + 1; } void Bu::Url::parseHost( Bu::String::const_iterator &i ) { Bu::String::const_iterator s = i; for( ; s && *s != '/'; s++ ) { if( *s == ':' ) { sHost.set( i, s ); i = s + 1; s = i.find('/'); Bu::String sPort( i, s ); iPort = strtol( sPort.getStr(), NULL, 10 ); i = s; return; } } sHost.set( i, s ); i = s; } void Bu::Url::parsePath( const Bu::String &sPath ) { Bu::String::const_iterator i = sPath.begin(); parsePath( i ); } void Bu::Url::parsePath( Bu::String::const_iterator &i ) { if( i ) { Bu::String::const_iterator s = i.find('?'); sPath.set( i, s ); i = s + 1; if( s ) { parseParams( i ); } } else { sPath = "/"; } } void Bu::Url::parseParams( const Bu::String &sQuery ) { Bu::String::const_iterator i = sQuery.begin(); parseParams( i ); } void Bu::Url::parseParams( Bu::String::const_iterator &i ) { bool bName = true; Bu::String sName, sValue; for( Bu::String::const_iterator s = i; s; s++ ) { if( bName ) { if( *s == '&' ) { sName.set( i, s ); sValue.clear(); i = s + 1; addParam( decode( sName ), decode( sValue ) ); } else if( *s == '=' ) { sName.set( i, s ); i = s + 1; bName = false; } } else { if( *s == '&' ) { sValue.set( i, s ); i = s + 1; bName = true; addParam( decode( sName ), decode( sValue ) ); } } } if( i ) { if( bName ) { sName.set( i ); sValue.clear(); } else { sValue.set( i ); } addParam( decode( sName ), decode( sValue ) ); } } void Bu::Url::addParam( const Bu::String &n, const Bu::String &v ) { lParam.append( Param( n, v ) ); } void Bu::Url::clear() { sProtocol.clear(); sUser.clear(); sPass.clear(); sHost.clear(); sPath.clear(); iPort.clear(); } Bu::String Bu::Url::getFullPath() const { Bu::String sBuf = sPath; if( !lParam.isEmpty() ) { for( ParamList::const_iterator i = lParam.begin(); i; i++ ) { if( i == lParam.begin() ) sBuf += "?"; else sBuf += "&"; sBuf += encode( (*i).sName ); if( !(*i).sValue.isEmpty() ) { sBuf += "=" + encode( (*i).sValue ); } } } return sBuf; } Bu::String Bu::Url::getUrl() const { Bu::String sBuf = sProtocol + "://" + sHost + getFullPath(); return sBuf; }