1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
10 * \file zypp/url/UrlBase.cc
12 #include <zypp/url/UrlBase.h>
13 #include <zypp/base/String.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <arpa/inet.h>
23 // ---------------------------------------------------------------
25 ** authority = //[user [:password] @ ] host [:port]
27 ** host = hostname | IPv4 | "[" IPv6-IP "]" | "[v...]"
29 #define RX_SPLIT_AUTHORITY \
30 "^(([^:@]*)([:]([^@]*))?@)?(\\[[^]]+\\]|[^:]+)?([:](.*))?"
32 #define RX_VALID_SCHEME "^[a-zA-Z][a-zA-Z0-9\\.+-]*$"
34 #define RX_VALID_PORT "^[0-9]{1,5}$"
36 #define RX_VALID_HOSTNAME "^[[:alnum:]]+([\\.-][[:alnum:]]+)*$"
38 #define RX_VALID_HOSTIPV4 \
39 "^([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})$"
41 #define RX_VALID_HOSTIPV6 \
42 "^\\[[:a-fA-F0-9]+(:[0-9]{1,3}(\\.[0-9]{1,3}){3})?\\]$"
45 //////////////////////////////////////////////////////////////////////
47 { ////////////////////////////////////////////////////////////////////
49 ////////////////////////////////////////////////////////////////////
51 { //////////////////////////////////////////////////////////////////
54 // ---------------------------------------------------------------
56 ** URL asString() view option constants:
58 const ViewOptions ViewOptions::WITH_SCHEME = 0x0001;
59 const ViewOptions ViewOptions::WITH_USERNAME = 0x0002;
60 const ViewOptions ViewOptions::WITH_PASSWORD = 0x0004;
61 const ViewOptions ViewOptions::WITH_HOST = 0x0008;
62 const ViewOptions ViewOptions::WITH_PORT = 0x0010;
63 const ViewOptions ViewOptions::WITH_PATH_NAME = 0x0020;
64 const ViewOptions ViewOptions::WITH_PATH_PARAMS = 0x0040;
65 const ViewOptions ViewOptions::WITH_QUERY_STR = 0x0080;
66 const ViewOptions ViewOptions::WITH_FRAGMENT = 0x0100;
67 const ViewOptions ViewOptions::EMPTY_AUTHORITY = 0x0200;
68 const ViewOptions ViewOptions::EMPTY_PATH_NAME = 0x0400;
69 const ViewOptions ViewOptions::EMPTY_PATH_PARAMS = 0x0800;
70 const ViewOptions ViewOptions::EMPTY_QUERY_STR = 0x1000;
71 const ViewOptions ViewOptions::EMPTY_FRAGMENT = 0x2000;
72 const ViewOptions ViewOptions::DEFAULTS = 0x07bb;
74 ViewOptions::WITH_SCHEME +
75 ViewOptions::WITH_USERNAME +
76 ViewOptions::WITH_HOST +
77 ViewOptions::WITH_PORT +
78 ViewOptions::WITH_PATH_NAME +
79 ViewOptions::WITH_QUERY_STR +
80 ViewOptions::WITH_FRAGMENT +
81 ViewOptions::EMPTY_AUTHORITY +
82 ViewOptions::EMPTY_PATH_NAME;
86 // ---------------------------------------------------------------
88 ** Behaviour configuration variables.
90 typedef std::map< std::string, std::string > UrlConfig;
93 // ---------------------------------------------------------------
95 * \brief Internal data used by UrlBase.
103 UrlBaseData(const UrlConfig &conf)
115 std::string pathname;
116 std::string pathparams;
117 std::string querystr;
118 std::string fragment;
122 // ---------------------------------------------------------------
124 ** Anonymous/internal utility namespace:
126 namespace // anonymous
129 // -------------------------------------------------------------
131 checkUrlData(const std::string &data,
132 const std::string &name,
133 const std::string ®x,
136 if( regx.empty() || regx == "^$")
138 ZYPP_THROW(UrlNotAllowedException(
139 std::string("Url scheme does not allow a " + name)
147 str::regex rex(regx);
148 valid = str::regex_match(data, rex);
157 ZYPP_THROW(UrlBadComponentException(
158 std::string("Invalid " + name + " component '" +
164 ZYPP_THROW(UrlBadComponentException(
165 std::string("Invalid " + name + " component")
175 // ---------------------------------------------------------------
183 // ---------------------------------------------------------------
185 : m_data( new UrlBaseData())
191 // ---------------------------------------------------------------
192 UrlBase::UrlBase(const UrlBase &url)
193 : m_data( new UrlBaseData( *(url.m_data)))
198 // ---------------------------------------------------------------
199 UrlBase::UrlBase(const std::string &scheme,
200 const std::string &authority,
201 const std::string &pathdata,
202 const std::string &querystr,
203 const std::string &fragment)
204 : m_data( new UrlBaseData())
207 init(scheme, authority, pathdata, querystr, fragment);
211 // ---------------------------------------------------------------
213 UrlBase::init(const std::string &scheme,
214 const std::string &authority,
215 const std::string &pathdata,
216 const std::string &querystr,
217 const std::string &fragment)
220 setAuthority(authority);
221 setPathData(pathdata);
222 setQueryString(querystr);
223 setFragment(fragment, zypp::url::E_ENCODED);
227 // ---------------------------------------------------------------
231 config("sep_pathparams", ";");
232 config("psep_pathparam", ",");
233 config("vsep_pathparam", "=");
235 config("psep_querystr", "&");
236 config("vsep_querystr", "=");
238 config("safe_username", "~!$&'()*+=,;");
239 config("safe_password", "~!$&'()*+=,:;");
240 config("safe_hostname", "[:]");
241 config("safe_pathname", "~!$&'()*+=,:@/");
242 config("safe_pathparams", "~!$&'()*+=,:;@/");
243 config("safe_querystr", "~!$&'()*+=,:;@/?");
244 config("safe_fragment", "~!$&'()*+=,:;@/?");
246 config("with_authority", "y");
247 config("require_scheme", "y");
249 config("rx_username", "^([a-zA-Z0-9!$&'\\(\\)*+=,;~\\._-]|%[a-fA-F0-9]{2})+$");
250 config("rx_password", "^([a-zA-Z0-9!$&'\\(\\)*+=,:;~\\._-]|%[a-fA-F0-9]{2})+$");
252 config("rx_pathname", "^([a-zA-Z0-9!$&'\\(\\)*+=,:@/~\\._-]|%[a-fA-F0-9]{2})+$");
253 config("rx_pathparams", "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/~\\._-]|%[a-fA-F0-9]{2})+$");
255 config("rx_querystr", "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
256 config("rx_fragment", "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
260 // ---------------------------------------------------------------
262 UrlBase::config(const std::string &opt, const std::string &val)
264 m_data->config[opt] = val;
268 // ---------------------------------------------------------------
270 UrlBase::config(const std::string &opt) const
272 UrlConfig::const_iterator v( m_data->config.find(opt));
273 if( v != m_data->config.end())
276 return std::string();
280 // ---------------------------------------------------------------
282 UrlBase::getViewOptions() const
284 return m_data->vopts;
288 // ---------------------------------------------------------------
290 UrlBase::setViewOptions(const ViewOptions &vopts)
292 m_data->vopts = vopts;
296 // ---------------------------------------------------------------
300 zypp::url::UrlConfig config(m_data->config);
301 zypp::url::ViewOptions vopts(m_data->vopts);
302 *m_data = UrlBaseData();
303 m_data->config = config;
304 m_data->vopts = vopts;
308 // ---------------------------------------------------------------
310 UrlBase::clone() const
312 return new UrlBase(*this);
316 // ---------------------------------------------------------------
317 zypp::url::UrlSchemes
318 UrlBase::getKnownSchemes() const
324 // ---------------------------------------------------------------
326 UrlBase::isKnownScheme(const std::string &scheme) const
328 std::string lscheme( str::toLower(scheme));
329 UrlSchemes schemes( getKnownSchemes());
330 UrlSchemes::const_iterator s;
332 for(s=schemes.begin(); s!=schemes.end(); ++s)
334 if( lscheme == str::toLower(*s))
341 // ---------------------------------------------------------------
343 UrlBase::isValidScheme(const std::string &scheme) const
348 str::regex rex(RX_VALID_SCHEME);
349 valid = str::regex_match(scheme, rex);
354 if((scheme.empty() && config("require_scheme") != "y") || valid)
356 std::string lscheme( str::toLower(scheme));
357 UrlSchemes schemes( getKnownSchemes());
362 UrlSchemes::const_iterator s;
363 for(s=schemes.begin(); s!=schemes.end(); ++s)
365 if( lscheme == str::toLower(*s))
373 // ---------------------------------------------------------------
375 UrlBase::isValid() const
377 return !getScheme().empty();
381 // ---------------------------------------------------------------
383 UrlBase::asString() const
385 return asString(getViewOptions());
389 // ---------------------------------------------------------------
391 UrlBase::asString(const zypp::url::ViewOptions &opts) const
396 if( opts.has(ViewOptions::WITH_SCHEME))
398 tmp.scheme = getScheme();
399 if( !tmp.scheme.empty())
401 url += tmp.scheme + ":";
403 if( opts.has(ViewOptions::WITH_HOST))
405 tmp.host = getHost(zypp::url::E_ENCODED);
406 if( !tmp.host.empty())
410 if( opts.has(ViewOptions::WITH_USERNAME))
412 tmp.user = getUsername(zypp::url::E_ENCODED);
413 if( !tmp.user.empty())
417 if( opts.has(ViewOptions::WITH_PASSWORD))
419 tmp.pass = getPassword(zypp::url::E_ENCODED);
420 if( !tmp.pass.empty())
422 url += ":" + tmp.pass;
431 if( opts.has(ViewOptions::WITH_PORT))
433 tmp.port = getPort();
434 if( !tmp.port.empty())
436 url += ":" + tmp.port;
441 else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
448 if( opts.has(ViewOptions::WITH_PATH_NAME))
450 tmp.pathname = getPathName(zypp::url::E_ENCODED);
451 if( !tmp.pathname.empty())
453 if( (!tmp.host.empty() || opts.has(ViewOptions::EMPTY_AUTHORITY))
454 && (tmp.pathname.at(0) != '/'))
460 if( opts.has(ViewOptions::WITH_PATH_PARAMS))
462 tmp.pathparams = getPathParams();
463 if( !tmp.pathparams.empty())
465 url += ";" + tmp.pathparams;
467 else if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
473 else if( opts.has(ViewOptions::EMPTY_PATH_NAME))
476 if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
483 if( opts.has(ViewOptions::WITH_QUERY_STR))
485 tmp.querystr = getQueryString();
486 if( !tmp.querystr.empty())
488 url += "?" + tmp.querystr;
490 else if( opts.has(ViewOptions::EMPTY_QUERY_STR))
496 if( opts.has(ViewOptions::WITH_FRAGMENT))
498 tmp.fragment = getFragment(zypp::url::E_ENCODED);
499 if( !tmp.fragment.empty())
501 url += "#" + tmp.fragment;
503 else if( opts.has(ViewOptions::EMPTY_FRAGMENT))
513 // ---------------------------------------------------------------
515 UrlBase::getScheme() const
517 return m_data->scheme;
521 // ---------------------------------------------------------------
523 UrlBase::getAuthority() const
526 if( !getHost(zypp::url::E_ENCODED).empty())
528 if( !getUsername(zypp::url::E_ENCODED).empty())
530 str = getUsername(zypp::url::E_ENCODED);
531 if( !getPassword(zypp::url::E_ENCODED).empty())
533 str += ":" + getPassword(zypp::url::E_ENCODED);
538 str += getHost(zypp::url::E_ENCODED);
539 if( !getPort().empty())
541 str += ":" + getPort();
548 // ---------------------------------------------------------------
550 UrlBase::getPathData() const
552 return getPathName(zypp::url::E_ENCODED) +
553 config("sep_pathparams") +
558 // ---------------------------------------------------------------
560 UrlBase::getQueryString() const
562 return m_data->querystr;
566 // ---------------------------------------------------------------
568 UrlBase::getFragment(EEncoding eflag) const
570 if(eflag == zypp::url::E_DECODED)
571 return zypp::url::decode(m_data->fragment);
573 return m_data->fragment;
577 // ---------------------------------------------------------------
579 UrlBase::getUsername(EEncoding eflag) const
581 if(eflag == zypp::url::E_DECODED)
582 return zypp::url::decode(m_data->user);
588 // ---------------------------------------------------------------
590 UrlBase::getPassword(EEncoding eflag) const
592 if(eflag == zypp::url::E_DECODED)
593 return zypp::url::decode(m_data->pass);
599 // ---------------------------------------------------------------
601 UrlBase::getHost(EEncoding eflag) const
603 if(eflag == zypp::url::E_DECODED)
604 return zypp::url::decode(m_data->host);
610 // ---------------------------------------------------------------
612 UrlBase::getPort() const
618 // ---------------------------------------------------------------
620 UrlBase::getPathName(EEncoding eflag) const
622 if(eflag == zypp::url::E_DECODED)
623 return zypp::url::decode(m_data->pathname);
625 return m_data->pathname;
629 // ---------------------------------------------------------------
631 UrlBase::getPathParams() const
633 return m_data->pathparams;
637 // ---------------------------------------------------------------
639 UrlBase::getPathParamsVec() const
641 zypp::url::ParamVec pvec;
642 if( config("psep_pathparam").empty())
644 pvec.push_back(getPathParams());
651 config("psep_pathparam")
658 // ---------------------------------------------------------------
660 UrlBase::getPathParamsMap(EEncoding eflag) const
662 if( config("psep_pathparam").empty() ||
663 config("vsep_pathparam").empty())
665 ZYPP_THROW(UrlNotSupportedException(
666 "Path parameter parsing not supported for this URL"
669 zypp::url::ParamMap pmap;
673 config("psep_pathparam"),
674 config("vsep_pathparam"),
681 // ---------------------------------------------------------------
683 UrlBase::getPathParam(const std::string ¶m, EEncoding eflag) const
685 zypp::url::ParamMap pmap( getPathParamsMap( eflag));
686 zypp::url::ParamMap::const_iterator i( pmap.find(param));
688 return i != pmap.end() ? i->second : std::string();
692 // ---------------------------------------------------------------
694 UrlBase::getQueryStringVec() const
696 zypp::url::ParamVec pvec;
697 if( config("psep_querystr").empty())
699 pvec.push_back(getQueryString());
706 config("psep_querystr")
713 // ---------------------------------------------------------------
715 UrlBase::getQueryStringMap(EEncoding eflag) const
717 if( config("psep_querystr").empty() ||
718 config("vsep_querystr").empty())
720 ZYPP_THROW(UrlNotSupportedException(
721 "Query string parsing not supported for this URL"
724 zypp::url::ParamMap pmap;
728 config("psep_querystr"),
729 config("vsep_querystr"),
736 // ---------------------------------------------------------------
738 UrlBase::getQueryParam(const std::string ¶m, EEncoding eflag) const
740 zypp::url::ParamMap pmap( getQueryStringMap( eflag));
741 zypp::url::ParamMap::const_iterator i( pmap.find(param));
743 return i != pmap.end() ? i->second : std::string();
747 // ---------------------------------------------------------------
749 UrlBase::setScheme(const std::string &scheme)
751 if( isValidScheme(scheme))
753 m_data->scheme = str::toLower(scheme);
758 ZYPP_THROW(UrlBadComponentException(
759 std::string("Url scheme is a required component")
764 ZYPP_THROW(UrlBadComponentException(
765 std::string("Invalid Url scheme '" + scheme + "'")
771 // ---------------------------------------------------------------
773 UrlBase::setAuthority(const std::string &authority)
780 str::regex rex(RX_SPLIT_AUTHORITY);
781 ret = str::regex_match(authority, out, rex);
786 if( ret && out.size() == 8)
788 setUsername(out[2].str(), zypp::url::E_ENCODED);
789 setPassword(out[4].str(), zypp::url::E_ENCODED);
790 setHost(out[5].str());
791 setPort(out[7].str());
795 ZYPP_THROW(UrlParsingException(
796 "Unable to parse Url authority"
801 // ---------------------------------------------------------------
803 UrlBase::setPathData(const std::string &pathdata)
805 size_t pos = std::string::npos;
806 std::string sep(config("sep_pathparams"));
809 pos = pathdata.find(sep);
811 if( pos != std::string::npos)
813 setPathName(pathdata.substr(0, pos),
814 zypp::url::E_ENCODED);
815 setPathParams(pathdata.substr(pos + 1));
819 setPathName(pathdata,
820 zypp::url::E_ENCODED);
826 // ---------------------------------------------------------------
828 UrlBase::setQueryString(const std::string &querystr)
830 if( querystr.empty())
832 m_data->querystr = querystr;
836 checkUrlData(querystr, "query string", config("rx_querystr"));
838 m_data->querystr = querystr;
843 // ---------------------------------------------------------------
845 UrlBase::setFragment(const std::string &fragment,
848 if( fragment.empty())
850 m_data->fragment = fragment;
854 if(eflag == zypp::url::E_ENCODED)
856 checkUrlData(fragment, "fragment", config("rx_fragment"));
858 m_data->fragment = fragment;
862 m_data->fragment = zypp::url::encode(
863 fragment, config("safe_password")
870 // ---------------------------------------------------------------
872 UrlBase::setUsername(const std::string &user,
881 if( config("with_authority") != "y")
883 ZYPP_THROW(UrlNotAllowedException(
884 std::string("Url scheme does not allow a username")
888 if(eflag == zypp::url::E_ENCODED)
890 checkUrlData(user, "username", config("rx_username"));
896 m_data->user = zypp::url::encode(
897 user, config("safe_username")
904 // ---------------------------------------------------------------
906 UrlBase::setPassword(const std::string &pass,
915 if( config("with_authority") != "y")
917 ZYPP_THROW(UrlNotAllowedException(
918 std::string("Url scheme does not allow a password")
922 if(eflag == zypp::url::E_ENCODED)
924 checkUrlData(pass, "password", config("rx_password"), false);
930 m_data->pass = zypp::url::encode(
931 pass, config("safe_password")
938 // ---------------------------------------------------------------
940 UrlBase::setHost(const std::string &host)
948 if( config("with_authority") != "y")
950 ZYPP_THROW(UrlNotAllowedException(
951 std::string("Url scheme does not allow a host")
955 if( isValidHost(host))
959 // always decode in case isValidHost()
960 // is reimplemented and supports also
961 // the [v ... ] notation.
962 if( host.at(0) == '[')
964 temp = str::toUpper(zypp::url::decode(host));
968 temp = str::toLower(zypp::url::decode(host));
971 m_data->host = zypp::url::encode(
972 temp, config("safe_hostname")
977 ZYPP_THROW(UrlBadComponentException(
978 std::string("Invalid host argument '" + host + "'")
985 // ---------------------------------------------------------------
987 UrlBase::setPort(const std::string &port)
995 if( config("with_authority") != "y")
997 ZYPP_THROW(UrlNotAllowedException(
998 std::string("Url scheme does not allow a port")
1002 if( isValidPort(port))
1004 m_data->port = port;
1008 ZYPP_THROW(UrlBadComponentException(
1009 std::string("Invalid host argument '" + port + "'")
1016 // ---------------------------------------------------------------
1018 UrlBase::setPathName(const std::string &path,
1023 m_data->pathname = path;
1028 if(eflag == zypp::url::E_ENCODED)
1030 checkUrlData(path, "path name", config("rx_pathname"));
1032 data = cleanupPathName(zypp::url::decode(path));
1036 data = cleanupPathName(path);
1039 m_data->pathname = zypp::url::encode(
1040 data, config("safe_pathname")
1046 // ---------------------------------------------------------------
1048 UrlBase::setPathParams(const std::string ¶ms)
1052 m_data->pathparams = params;
1056 checkUrlData(params, "path parameters", config("rx_pathparams"));
1058 m_data->pathparams = params;
1063 // ---------------------------------------------------------------
1065 UrlBase::setPathParamsVec(const zypp::url::ParamVec &pvec)
1070 config("psep_pathparam")
1076 // ---------------------------------------------------------------
1078 UrlBase::setPathParamsMap(const zypp::url::ParamMap &pmap)
1080 if( config("psep_pathparam").empty() ||
1081 config("vsep_pathparam").empty())
1083 ZYPP_THROW(UrlNotSupportedException(
1084 "Path Parameter parsing not supported for this URL"
1090 config("psep_pathparam"),
1091 config("vsep_pathparam"),
1092 config("safe_pathparams")
1098 // ---------------------------------------------------------------
1100 UrlBase::setPathParam(const std::string ¶m, const std::string &value)
1102 zypp::url::ParamMap pmap( getPathParamsMap(zypp::url::E_DECODED));
1103 pmap[param] = value;
1104 setPathParamsMap(pmap);
1108 // ---------------------------------------------------------------
1110 UrlBase::setQueryStringVec(const zypp::url::ParamVec &pvec)
1115 config("psep_querystr")
1121 // ---------------------------------------------------------------
1123 UrlBase::setQueryStringMap(const zypp::url::ParamMap &pmap)
1125 if( config("psep_querystr").empty() ||
1126 config("vsep_querystr").empty())
1128 ZYPP_THROW(UrlNotSupportedException(
1129 "Query string parsing not supported for this URL"
1135 config("psep_querystr"),
1136 config("vsep_querystr"),
1137 config("safe_querystr")
1142 // ---------------------------------------------------------------
1144 UrlBase::setQueryParam(const std::string ¶m, const std::string &value)
1146 zypp::url::ParamMap pmap( getQueryStringMap(zypp::url::E_DECODED));
1147 pmap[param] = value;
1148 setQueryStringMap(pmap);
1152 // ---------------------------------------------------------------
1154 UrlBase::cleanupPathName(const std::string &path)
1158 while( pos < path.length() && path.at(pos) == '/')
1163 // make sure, there is not more than
1164 // _one_ leading "/" in the path name.
1165 return path.substr(pos - 1);
1168 return std::string(path);
1172 // ---------------------------------------------------------------
1174 UrlBase::isValidHost(const std::string &host)
1178 str::regex regx(RX_VALID_HOSTIPV6);
1179 if( str::regex_match(host, regx))
1182 std::string temp( host.substr(1, host.size()-2));
1184 return inet_pton(AF_INET6, temp.c_str(), &ip) > 0;
1188 // matches also IPv4 dotted-decimal adresses...
1189 std::string temp( zypp::url::decode(host));
1190 str::regex regx(RX_VALID_HOSTNAME);
1191 return str::regex_match(temp, regx);
1201 // ---------------------------------------------------------------
1203 UrlBase::isValidPort(const std::string &port)
1207 str::regex regx(RX_VALID_PORT);
1208 if( str::regex_match(port, regx))
1210 long pnum = str::strtonum<long>(port);
1211 return ( pnum >= 1 && pnum <= USHRT_MAX);
1221 //////////////////////////////////////////////////////////////////
1223 ////////////////////////////////////////////////////////////////////
1225 ////////////////////////////////////////////////////////////////////
1227 //////////////////////////////////////////////////////////////////////
1229 ** vim: set ts=2 sts=2 sw=2 ai et: