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 toString() 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)
135 if( regx.empty() || regx == "^$")
137 throw std::invalid_argument(
138 std::string("Url scheme does not allow a " +
143 if( !str::regex_match(data, str::regex(regx)))
145 throw std::invalid_argument(
146 std::string("Invalid " + name + " argument '" +
155 // ---------------------------------------------------------------
163 // ---------------------------------------------------------------
165 : m_data( new UrlBaseData())
171 // ---------------------------------------------------------------
172 UrlBase::UrlBase(const UrlBase &url)
173 : m_data( new UrlBaseData( *(url.m_data)))
178 // ---------------------------------------------------------------
179 UrlBase::UrlBase(const std::string &scheme,
180 const std::string &authority,
181 const std::string &pathdata,
182 const std::string &querystr,
183 const std::string &fragment)
184 : m_data( new UrlBaseData())
187 init(scheme, authority, pathdata, querystr, fragment);
191 // ---------------------------------------------------------------
193 UrlBase::init(const std::string &scheme,
194 const std::string &authority,
195 const std::string &pathdata,
196 const std::string &querystr,
197 const std::string &fragment)
200 setAuthority(authority);
201 setPathData(pathdata);
202 setQueryString(querystr);
203 setFragment(fragment, zypp::url::E_ENCODED);
207 // ---------------------------------------------------------------
211 config("sep_pathparams", ";");
212 config("psep_pathparam", ",");
213 config("vsep_pathparam", "=");
215 config("psep_querystr", "&");
216 config("vsep_querystr", "=");
218 config("safe_username", "~!$&'()*+=,;");
219 config("safe_password", "~!$&'()*+=,:;");
220 config("safe_hostname", "[:]");
221 config("safe_pathname", "~!$&'()*+=,:@/");
222 config("safe_pathparams", "~!$&'()*+=,:;@/");
223 config("safe_querystr", "~!$&'()*+=,:;@/?");
224 config("safe_fragment", "~!$&'()*+=,:;@/?");
226 config("with_authority", "y");
228 config("rx_username", "^([a-zA-Z0-9!$&'\\(\\)*+=,;~\\._-]|%[a-fA-F0-9]{2})+$");
229 config("rx_password", "^([a-zA-Z0-9!$&'\\(\\)*+=,:;~\\._-]|%[a-fA-F0-9]{2})+$");
231 config("rx_pathname", "^([a-zA-Z0-9!$&'\\(\\)*+=,:@/~\\._-]|%[a-fA-F0-9]{2})+$");
232 config("rx_pathparams", "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/~\\._-]|%[a-fA-F0-9]{2})+$");
234 config("rx_querystr", "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
235 config("rx_fragment", "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
239 // ---------------------------------------------------------------
241 UrlBase::config(const std::string &opt, const std::string &val)
243 m_data->config[opt] = val;
247 // ---------------------------------------------------------------
249 UrlBase::config(const std::string &opt) const
251 UrlConfig::const_iterator v( m_data->config.find(opt));
252 if( v != m_data->config.end())
255 return std::string();
259 // ---------------------------------------------------------------
261 UrlBase::getViewOptions() const
263 return m_data->vopts;
267 // ---------------------------------------------------------------
269 UrlBase::setViewOptions(const ViewOptions &vopts)
271 m_data->vopts = vopts;
275 // ---------------------------------------------------------------
279 zypp::url::UrlConfig config(m_data->config);
280 zypp::url::ViewOptions vopts(m_data->vopts);
281 *m_data = UrlBaseData();
282 m_data->config = config;
283 m_data->vopts = vopts;
287 // ---------------------------------------------------------------
289 UrlBase::clone() const
291 return new UrlBase(*this);
295 // ---------------------------------------------------------------
296 zypp::url::UrlSchemes
297 UrlBase::getKnownSchemes() const
303 // ---------------------------------------------------------------
305 UrlBase::isKnownScheme(const std::string &scheme) const
307 std::string lscheme( str::toLower(scheme));
308 UrlSchemes schemes( getKnownSchemes());
309 UrlSchemes::const_iterator s;
311 for(s=schemes.begin(); s!=schemes.end(); ++s)
313 if( lscheme == str::toLower(*s))
320 // ---------------------------------------------------------------
322 UrlBase::isValidScheme(const std::string &scheme) const
325 str::regex_match(scheme, str::regex(RX_VALID_SCHEME)))
327 std::string lscheme( str::toLower(scheme));
328 UrlSchemes schemes( getKnownSchemes());
333 UrlSchemes::const_iterator s;
334 for(s=schemes.begin(); s!=schemes.end(); ++s)
336 if( lscheme == str::toLower(*s))
344 // ---------------------------------------------------------------
346 UrlBase::isValid() const
348 return !getScheme().empty();
352 // ---------------------------------------------------------------
354 UrlBase::toString() const
356 return toString(getViewOptions());
360 // ---------------------------------------------------------------
362 UrlBase::toString(const zypp::url::ViewOptions &opts) const
367 if( opts.has(ViewOptions::WITH_SCHEME))
369 tmp.scheme = getScheme();
370 if( !tmp.scheme.empty())
372 url += tmp.scheme + ":";
374 if( opts.has(ViewOptions::WITH_HOST))
376 tmp.host = getHost(zypp::url::E_ENCODED);
377 if( !tmp.host.empty())
381 if( opts.has(ViewOptions::WITH_USERNAME))
383 tmp.user = getUsername(zypp::url::E_ENCODED);
384 if( !tmp.user.empty())
388 if( opts.has(ViewOptions::WITH_PASSWORD))
390 tmp.pass = getPassword(zypp::url::E_ENCODED);
391 if( !tmp.pass.empty())
393 url += ":" + tmp.pass;
402 if( opts.has(ViewOptions::WITH_PORT))
404 tmp.port = getPort();
405 if( !tmp.port.empty())
407 url += ":" + tmp.port;
412 else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
419 if( opts.has(ViewOptions::WITH_PATH_NAME))
421 tmp.pathname = getPathName(zypp::url::E_ENCODED);
422 if( !tmp.pathname.empty())
424 if( (!tmp.host.empty() || opts.has(ViewOptions::EMPTY_AUTHORITY))
425 && (tmp.pathname.at(0) != '/'))
431 if( opts.has(ViewOptions::WITH_PATH_PARAMS))
433 tmp.pathparams = getPathParams();
434 if( !tmp.pathparams.empty())
436 url += ";" + tmp.pathparams;
438 else if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
444 else if( opts.has(ViewOptions::EMPTY_PATH_NAME))
447 if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
454 if( opts.has(ViewOptions::WITH_QUERY_STR))
456 tmp.querystr = getQueryString();
457 if( !tmp.querystr.empty())
459 url += "?" + tmp.querystr;
461 else if( opts.has(ViewOptions::EMPTY_QUERY_STR))
467 if( opts.has(ViewOptions::WITH_FRAGMENT))
469 tmp.fragment = getFragment(zypp::url::E_ENCODED);
470 if( !tmp.fragment.empty())
472 url += "#" + tmp.fragment;
474 else if( opts.has(ViewOptions::EMPTY_FRAGMENT))
484 // ---------------------------------------------------------------
486 UrlBase::getScheme() const
488 return m_data->scheme;
492 // ---------------------------------------------------------------
494 UrlBase::getAuthority() const
497 if( !getHost(zypp::url::E_ENCODED).empty())
499 if( !getUsername(zypp::url::E_ENCODED).empty())
501 str = getUsername(zypp::url::E_ENCODED);
502 if( !getPassword(zypp::url::E_ENCODED).empty())
504 str += ":" + getPassword(zypp::url::E_ENCODED);
509 str += getHost(zypp::url::E_ENCODED);
510 if( !getPort().empty())
512 str += ":" + getPort();
519 // ---------------------------------------------------------------
521 UrlBase::getPathData() const
523 return getPathName(zypp::url::E_ENCODED) +
524 config("sep_pathparams") +
529 // ---------------------------------------------------------------
531 UrlBase::getQueryString() const
533 return m_data->querystr;
537 // ---------------------------------------------------------------
539 UrlBase::getFragment(EEncoding eflag) const
541 if(eflag == zypp::url::E_DECODED)
542 return zypp::url::decode(m_data->fragment);
544 return m_data->fragment;
548 // ---------------------------------------------------------------
550 UrlBase::getUsername(EEncoding eflag) const
552 if(eflag == zypp::url::E_DECODED)
553 return zypp::url::decode(m_data->user);
559 // ---------------------------------------------------------------
561 UrlBase::getPassword(EEncoding eflag) const
563 if(eflag == zypp::url::E_DECODED)
564 return zypp::url::decode(m_data->pass);
570 // ---------------------------------------------------------------
572 UrlBase::getHost(EEncoding eflag) const
574 if(eflag == zypp::url::E_DECODED)
575 return zypp::url::decode(m_data->host);
581 // ---------------------------------------------------------------
583 UrlBase::getPort() const
589 // ---------------------------------------------------------------
591 UrlBase::getPathName(EEncoding eflag) const
593 if(eflag == zypp::url::E_DECODED)
594 return zypp::url::decode(m_data->pathname);
596 return m_data->pathname;
600 // ---------------------------------------------------------------
602 UrlBase::getPathParams() const
604 return m_data->pathparams;
608 // ---------------------------------------------------------------
610 UrlBase::getPathParamsVec() const
612 zypp::url::ParamVec pvec;
616 config("psep_pathparam")
622 // ---------------------------------------------------------------
624 UrlBase::getPathParamsMap(EEncoding eflag) const
626 zypp::url::ParamMap pmap;
630 config("psep_pathparam"),
631 config("vsep_pathparam"),
638 // ---------------------------------------------------------------
640 UrlBase::getPathParam(const std::string ¶m, EEncoding eflag) const
642 zypp::url::ParamMap pmap( getPathParamsMap( eflag));
643 zypp::url::ParamMap::const_iterator i( pmap.find(param));
645 return i != pmap.end() ? i->second : std::string();
649 // ---------------------------------------------------------------
651 UrlBase::getQueryStringVec() const
653 zypp::url::ParamVec pvec;
657 config("psep_querystr")
663 // ---------------------------------------------------------------
665 UrlBase::getQueryStringMap(EEncoding eflag) const
667 zypp::url::ParamMap pmap;
671 config("psep_querystr"),
672 config("vsep_querystr"),
679 // ---------------------------------------------------------------
681 UrlBase::getQueryParam(const std::string ¶m, EEncoding eflag) const
683 zypp::url::ParamMap pmap( getQueryStringMap( eflag));
684 zypp::url::ParamMap::const_iterator i( pmap.find(param));
686 return i != pmap.end() ? i->second : std::string();
690 // ---------------------------------------------------------------
692 UrlBase::setScheme(const std::string &scheme)
694 if( isValidScheme(scheme))
696 m_data->scheme = str::toLower(scheme);
700 throw std::invalid_argument(
701 std::string("Invalid Url scheme '" + scheme + "'")
707 // ---------------------------------------------------------------
709 UrlBase::setAuthority(const std::string &authority)
711 str::regex rex(RX_SPLIT_AUTHORITY);
713 bool ret = str::regex_match(authority, out, rex);
715 if( ret && out.size() == 8)
717 setUsername(out[2].str(), zypp::url::E_ENCODED);
718 setPassword(out[4].str(), zypp::url::E_ENCODED);
719 setHost(out[5].str());
720 setPort(out[7].str());
724 throw std::invalid_argument(
725 "Unable to parse Url authority"
730 // ---------------------------------------------------------------
732 UrlBase::setPathData(const std::string &pathdata)
734 size_t pos = std::string::npos;
735 std::string sep(config("sep_pathparams"));
738 pos = pathdata.find(sep);
740 if( pos != std::string::npos)
742 setPathName(pathdata.substr(0, pos),
743 zypp::url::E_ENCODED);
744 setPathParams(pathdata.substr(pos + 1));
748 setPathName(pathdata,
749 zypp::url::E_ENCODED);
755 // ---------------------------------------------------------------
757 UrlBase::setQueryString(const std::string &querystr)
759 if( querystr.empty())
761 m_data->querystr = querystr;
765 checkUrlData(querystr, "query string", config("rx_querystr"));
767 m_data->querystr = querystr;
772 // ---------------------------------------------------------------
774 UrlBase::setFragment(const std::string &fragment,
777 if( fragment.empty())
779 m_data->fragment = fragment;
783 if(eflag == zypp::url::E_ENCODED)
785 checkUrlData(fragment, "fragment", config("rx_fragment"));
787 m_data->fragment = fragment;
791 m_data->fragment = zypp::url::encode(
792 fragment, config("safe_password")
799 // ---------------------------------------------------------------
801 UrlBase::setUsername(const std::string &user,
810 if( config("with_authority") != "y")
812 throw std::invalid_argument(
813 std::string("Url scheme does not allow a username")
817 if(eflag == zypp::url::E_ENCODED)
819 checkUrlData(user, "username", config("rx_username"));
825 m_data->user = zypp::url::encode(
826 user, config("safe_username")
833 // ---------------------------------------------------------------
835 UrlBase::setPassword(const std::string &pass,
844 if( config("with_authority") != "y")
846 throw std::invalid_argument(
847 std::string("Url scheme does not allow a password")
851 if(eflag == zypp::url::E_ENCODED)
853 checkUrlData(pass, "password", config("rx_password"));
859 m_data->pass = zypp::url::encode(
860 pass, config("safe_password")
867 // ---------------------------------------------------------------
869 UrlBase::setHost(const std::string &host)
877 if( config("with_authority") != "y")
879 throw std::invalid_argument(
880 std::string("Url scheme does not allow a host")
884 if( isValidHost(host))
887 if( host.at(0) == '[')
889 temp = str::toUpper(zypp::url::decode(host));
893 temp = str::toLower(zypp::url::decode(host));
896 m_data->host = zypp::url::encode(
897 temp, config("safe_hostname")
902 throw std::invalid_argument(
903 std::string("Invalid host argument '" + host + "'")
910 // ---------------------------------------------------------------
912 UrlBase::setPort(const std::string &port)
920 if( config("with_authority") != "y")
922 throw std::invalid_argument(
923 std::string("Url scheme does not allow a port")
927 if( isValidPort(port))
933 throw std::invalid_argument(
934 std::string("Invalid host argument '" + port + "'")
941 // ---------------------------------------------------------------
943 UrlBase::setPathName(const std::string &path,
948 m_data->pathname = path;
953 if(eflag == zypp::url::E_ENCODED)
955 data = cleanupPathName(zypp::url::decode(path));
959 data = cleanupPathName(path);
962 m_data->pathname = zypp::url::encode(
963 data, config("safe_pathname")
969 // ---------------------------------------------------------------
971 UrlBase::setPathParams(const std::string ¶ms)
975 m_data->pathparams = params;
979 checkUrlData(params, "path parameters", config("rx_pathparams"));
981 m_data->pathparams = params;
986 // ---------------------------------------------------------------
988 UrlBase::setPathParamsVec(const zypp::url::ParamVec &pvec)
993 config("psep_pathparam")
999 // ---------------------------------------------------------------
1001 UrlBase::setPathParamsMap(const zypp::url::ParamMap &pmap)
1006 config("psep_pathparam"),
1007 config("vsep_pathparam"),
1008 config("safe_pathparams")
1014 // ---------------------------------------------------------------
1016 UrlBase::setPathParam(const std::string ¶m, const std::string &value)
1018 zypp::url::ParamMap pmap( getPathParamsMap(zypp::url::E_DECODED));
1019 pmap[param] = value;
1020 setPathParamsMap(pmap);
1024 // ---------------------------------------------------------------
1026 UrlBase::setQueryStringVec(const zypp::url::ParamVec &pvec)
1031 config("psep_querystr")
1037 // ---------------------------------------------------------------
1039 UrlBase::setQueryStringMap(const zypp::url::ParamMap &pmap)
1044 config("psep_querystr"),
1045 config("vsep_querystr"),
1046 config("safe_querystr")
1051 // ---------------------------------------------------------------
1053 UrlBase::setQueryParam(const std::string ¶m, const std::string &value)
1055 zypp::url::ParamMap pmap( getQueryStringMap(zypp::url::E_DECODED));
1056 pmap[param] = value;
1057 setQueryStringMap(pmap);
1061 // ---------------------------------------------------------------
1063 UrlBase::cleanupPathName(const std::string &path)
1067 while( pos < path.length() && path.at(pos) == '/')
1072 // make sure, there is not more than
1073 // _one_ leading "/" in the path name.
1074 return path.substr(pos - 1);
1077 return std::string(path);
1081 // ---------------------------------------------------------------
1083 UrlBase::isValidHost(const std::string &host)
1085 if( str::regex_match(host, str::regex(RX_VALID_HOSTIPV6)))
1089 if( inet_pton(AF_INET6, host.substr(1, host.size()-2).c_str(), &ip) > 0)
1096 // matches also IPv4 dotted-decimal adresses...
1097 std::string tmp( zypp::url::decode(host));
1098 return str::regex_match(tmp, str::regex(RX_VALID_HOSTNAME));
1103 // ---------------------------------------------------------------
1105 UrlBase::isValidPort(const std::string &port)
1107 if( str::regex_match(port, str::regex(RX_VALID_PORT)))
1109 long pnum = str::strtonum<long>(port);
1110 if( pnum >= 1 && pnum <= USHRT_MAX)
1119 //////////////////////////////////////////////////////////////////
1121 ////////////////////////////////////////////////////////////////////
1123 ////////////////////////////////////////////////////////////////////
1125 //////////////////////////////////////////////////////////////////////
1127 ** vim: set ts=2 sts=2 sw=2 ai et: