1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
10 * \file zypp/url/UrlBase.cc
12 #include <zypp/url/UrlBase.h>
13 #include <zypp/base/String.h>
14 #include <zypp/base/Gettext.h>
15 #include <zypp/base/Regex.h>
16 #include <zypp/base/StringV.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <arpa/inet.h>
27 // in the Estonian locale, a-z excludes t, for example. #302525
28 // http://en.wikipedia.org/wiki/Estonian_alphabet
29 #define a_zA_Z "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
31 // ---------------------------------------------------------------
33 ** authority = //[user [:password] @ ] host [:port]
35 ** host = hostname | IPv4 | "[" IPv6-IP "]" | "[v...]"
37 #define RX_VALID_SCHEME "^[" a_zA_Z "][" a_zA_Z "0-9\\.+-]*$"
39 #define RX_VALID_PORT "^[0-9]{1,5}$"
41 #define RX_VALID_HOSTNAME "^[[:alnum:]${_}]+([\\.-][[:alnum:]${_}]+)*$"
43 #define RX_VALID_HOSTIPV4 \
44 "^([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})$"
46 #define RX_VALID_HOSTIPV6 \
47 "^\\[[:a-fA-F0-9]+(:[0-9]{1,3}(\\.[0-9]{1,3}){3})?\\]$"
50 //////////////////////////////////////////////////////////////////////
52 { ////////////////////////////////////////////////////////////////////
54 ////////////////////////////////////////////////////////////////////
56 { //////////////////////////////////////////////////////////////////
59 // ---------------------------------------------------------------
61 ** URL asString() view option constants:
63 const ViewOption ViewOption::WITH_SCHEME = 0x0001;
64 const ViewOption ViewOption::WITH_USERNAME = 0x0002;
65 const ViewOption ViewOption::WITH_PASSWORD = 0x0004;
66 const ViewOption ViewOption::WITH_HOST = 0x0008;
67 const ViewOption ViewOption::WITH_PORT = 0x0010;
68 const ViewOption ViewOption::WITH_PATH_NAME = 0x0020;
69 const ViewOption ViewOption::WITH_PATH_PARAMS = 0x0040;
70 const ViewOption ViewOption::WITH_QUERY_STR = 0x0080;
71 const ViewOption ViewOption::WITH_FRAGMENT = 0x0100;
72 const ViewOption ViewOption::EMPTY_AUTHORITY = 0x0200;
73 const ViewOption ViewOption::EMPTY_PATH_NAME = 0x0400;
74 const ViewOption ViewOption::EMPTY_PATH_PARAMS = 0x0800;
75 const ViewOption ViewOption::EMPTY_QUERY_STR = 0x1000;
76 const ViewOption ViewOption::EMPTY_FRAGMENT = 0x2000;
77 const ViewOption ViewOption::DEFAULTS = 0x07bb;
79 const ViewOption ViewOption::hotfix1050625 = 0x8000;
81 const ViewOption ViewOption::DEFAULTS =
82 ViewOption::WITH_SCHEME +
83 ViewOption::WITH_USERNAME +
84 ViewOption::WITH_HOST +
85 ViewOption::WITH_PORT +
86 ViewOption::WITH_PATH_NAME +
87 ViewOption::WITH_QUERY_STR +
88 ViewOption::WITH_FRAGMENT +
89 ViewOption::EMPTY_AUTHORITY +
90 ViewOption::EMPTY_PATH_NAME;
93 // ---------------------------------------------------------------
94 ViewOption::ViewOption()
98 // ---------------------------------------------------------------
99 ViewOption::ViewOption(int option)
104 // ---------------------------------------------------------------
106 ** Behaviour configuration variables.
108 typedef std::map< std::string, std::string > UrlConfig;
111 // ---------------------------------------------------------------
113 /// \brief Hide passwords embedded in a querystr,
115 /// Stores the full querystring and maintains a safe version with
116 /// password field stripped. Url::asString will print the passwords
119 /// \see bsc#1050625: VUL-1: CVE-2017-9271: zypper: proxy credentials written to log files
126 SafeQuerystr( std::string rhs )
127 { _assign( std::move(rhs) ); }
129 SafeQuerystr & operator=( std::string rhs )
130 { _assign( std::move(rhs) ); return *this; }
133 operator const std::string &() const
136 const std::string & str() const
137 { return fullStr(); }
139 const std::string & str( const ViewOptions & viewopts_r ) const
140 { return (viewopts_r.has( ViewOptions::WITH_PASSWORD ) || viewopts_r.has( ViewOptions::hotfix1050625 )) ? fullStr() : safeStr(); }
142 const std::string & fullStr() const
143 { return _fullQuerytsr; }
145 const std::string & safeStr() const
146 { return _safeQuerytsr ? _safeQuerytsr.value() : _fullQuerytsr; }
149 void _assign( std::string && rhs )
151 _fullQuerytsr = std::move(rhs);
153 static constexpr std::string_view tag { "proxypass=" };
154 if ( _fullQuerytsr.find( tag ) != std::string::npos )
157 strv::split( _fullQuerytsr, "&", [&safe]( std::string_view val ) {
158 if ( val.substr( 0, tag.size() ) != tag ) {
159 if ( ! safe.empty() )
164 _safeQuerytsr = std::move(safe);
167 _safeQuerytsr = std::nullopt;
170 std::string _fullQuerytsr; ///<
171 std::optional<std::string> _safeQuerytsr; ///<.
175 * \brief Internal data used by UrlBase.
183 UrlBaseData(const UrlConfig &conf)
195 std::string pathname;
196 std::string pathparams;
197 SafeQuerystr querystr;
198 std::string fragment;
202 // ---------------------------------------------------------------
204 ** Anonymous/internal utility namespace:
206 namespace // anonymous
209 // -------------------------------------------------------------
211 checkUrlData(const std::string &data,
212 const std::string &name,
213 const std::string ®x,
216 if( regx.empty() || regx == "^$")
218 ZYPP_THROW(UrlNotAllowedException(
219 str::form(_("Url scheme does not allow a %s"), name.c_str())
227 str::regex rex(regx);
228 valid = str::regex_match(data, rex);
237 ZYPP_THROW(UrlBadComponentException(
238 str::form(_("Invalid %s component '%s'"),
239 name.c_str(), data.c_str())
244 ZYPP_THROW(UrlBadComponentException(
245 str::form(_("Invalid %s component"), name.c_str())
255 // ---------------------------------------------------------------
263 // ---------------------------------------------------------------
265 : m_data( new UrlBaseData())
271 // ---------------------------------------------------------------
272 UrlBase::UrlBase(const UrlBase &url)
273 : m_data( new UrlBaseData( *(url.m_data)))
278 // ---------------------------------------------------------------
279 UrlBase::UrlBase(const std::string &scheme,
280 const std::string &authority,
281 const std::string &pathdata,
282 const std::string &querystr,
283 const std::string &fragment)
284 : m_data( new UrlBaseData())
287 init(scheme, authority, pathdata, querystr, fragment);
291 // ---------------------------------------------------------------
293 UrlBase::init(const std::string &scheme,
294 const std::string &authority,
295 const std::string &pathdata,
296 const std::string &querystr,
297 const std::string &fragment)
299 if ( scheme.empty() && *pathdata.c_str() == '/' )
304 setAuthority(authority);
305 setPathData(pathdata);
306 setQueryString(querystr);
307 setFragment(fragment, zypp::url::E_ENCODED);
311 // ---------------------------------------------------------------
315 config("sep_pathparams", ";");
316 config("psep_pathparam", ",");
317 config("vsep_pathparam", "=");
319 config("psep_querystr", "&");
320 config("vsep_querystr", "=");
322 config("safe_username", "~!$&'()*+=,;");
323 config("safe_password", "~!$&'()*+=,:;");
324 config("safe_hostname", "[:]${_}");
325 config("safe_pathname", "~!$&'()*+=,:@/");
326 config("safe_pathparams", "~!$&'()*+=,:;@/");
327 config("safe_querystr", "~!$&'()*+=,:;@/?");
328 config("safe_fragment", "~!$&'()*+=,:;@/?");
331 // n=no (disallowed, exception if !empty)
332 config("with_authority", "y");
333 config("with_port", "y");
335 // y=yes (required but don't throw if empty)
336 // n=no (not required, ignore if empty)
337 // m=mandatory (exception if empty)
338 config("require_host", "n");
339 config("require_pathname","n");
341 // y=yes (encode 2. slash even if authority present)
342 // n=no (don't encode 2. slash if authority present)
343 config("path_encode_slash2", "n");
345 config("rx_username", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,;~\\._-]|%[a-fA-F0-9]{2})+$");
346 config("rx_password", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,:;~\\._-]|%[a-fA-F0-9]{2})+$");
348 config("rx_pathname", "^([" a_zA_Z "0-9!$&'\\(\\){}*+=,:@/~\\._-]|%[a-fA-F0-9]{2})+$");
349 config("rx_pathparams", "^([" a_zA_Z "0-9!$&'\\(\\){}*+=,:;@/~\\._-]|%[a-fA-F0-9]{2})+$");
351 config("rx_querystr", "^([" a_zA_Z "0-9!$&'\\(\\){}*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
352 config("rx_fragment", "^([" a_zA_Z "0-9!$&'\\(\\){}*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
356 // ---------------------------------------------------------------
358 UrlBase::config(const std::string &opt, const std::string &val)
360 m_data->config[opt] = val;
364 // ---------------------------------------------------------------
366 UrlBase::config(const std::string &opt) const
368 UrlConfig::const_iterator v( m_data->config.find(opt));
369 if( v != m_data->config.end())
372 return std::string();
376 // ---------------------------------------------------------------
378 UrlBase::getViewOptions() const
380 return m_data->vopts;
384 // ---------------------------------------------------------------
386 UrlBase::setViewOptions(const ViewOptions &vopts)
388 m_data->vopts = vopts;
392 // ---------------------------------------------------------------
396 zypp::url::UrlConfig config(m_data->config);
397 zypp::url::ViewOptions vopts(m_data->vopts);
398 *m_data = UrlBaseData();
399 m_data->config = config;
400 m_data->vopts = vopts;
404 // ---------------------------------------------------------------
406 UrlBase::clone() const
408 return new UrlBase(*this);
412 // ---------------------------------------------------------------
413 zypp::url::UrlSchemes
414 UrlBase::getKnownSchemes() const
420 // ---------------------------------------------------------------
422 UrlBase::isKnownScheme(const std::string &scheme) const
424 std::string lscheme( str::toLower(scheme));
425 UrlSchemes schemes( getKnownSchemes());
426 UrlSchemes::const_iterator s;
428 for(s=schemes.begin(); s!=schemes.end(); ++s)
430 if( lscheme == str::toLower(*s))
437 // ---------------------------------------------------------------
439 UrlBase::isValidScheme(const std::string &scheme) const
444 str::regex rex(RX_VALID_SCHEME);
445 valid = str::regex_match(scheme, rex);
452 std::string lscheme( str::toLower(scheme));
453 UrlSchemes schemes( getKnownSchemes());
458 UrlSchemes::const_iterator s;
459 for(s=schemes.begin(); s!=schemes.end(); ++s)
461 if( lscheme == str::toLower(*s))
469 // ---------------------------------------------------------------
471 UrlBase::isValid() const
474 ** scheme is the only mandatory component
475 ** for all url's and is already verified,
476 ** (except for empty Url instances), so
477 ** Url with empty scheme is never valid.
479 if( getScheme().empty())
482 std::string host( getHost(zypp::url::E_ENCODED));
483 if( host.empty() && config("require_host") != "n")
486 std::string path( getPathName(zypp::url::E_ENCODED));
487 if( path.empty() && config("require_pathname") != "n")
491 ** path has to begin with "/" if authority avaliable
492 ** if host is set after the pathname, we can't throw
494 if( !host.empty() && !path.empty() && path.at(0) != '/')
501 // ---------------------------------------------------------------
503 UrlBase::asString() const
505 return asString(getViewOptions());
508 std::string UrlBase::asString1050625() const
510 // Temp. fix to keep the proxypass in the query when writing the .repo files,
511 // but otherwise hiding it, when WITH_PASSWORD is not set.
512 return asString(getViewOptions()+ViewOptions::hotfix1050625);
515 // ---------------------------------------------------------------
517 UrlBase::asString(const zypp::url::ViewOptions &opts) const
522 if( opts.has(ViewOptions::WITH_SCHEME))
524 tmp.scheme = getScheme();
525 if( !tmp.scheme.empty())
527 url += tmp.scheme + ":";
529 if( opts.has(ViewOptions::WITH_HOST))
531 tmp.host = getHost(zypp::url::E_ENCODED);
532 if( !tmp.host.empty())
536 if( opts.has(ViewOptions::WITH_USERNAME))
538 tmp.user = getUsername(zypp::url::E_ENCODED);
539 if( !tmp.user.empty())
543 if( opts.has(ViewOptions::WITH_PASSWORD))
545 tmp.pass = getPassword(zypp::url::E_ENCODED);
546 if( !tmp.pass.empty())
548 url += ":" + tmp.pass;
557 if( opts.has(ViewOptions::WITH_PORT))
559 tmp.port = getPort();
560 if( !tmp.port.empty())
562 url += ":" + tmp.port;
566 else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
571 else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
578 if( opts.has(ViewOptions::WITH_PATH_NAME))
580 tmp.pathname = getPathName(zypp::url::E_ENCODED);
581 if( !tmp.pathname.empty())
583 if(url.find("/") != std::string::npos)
585 // Url contains authority (that may be empty),
586 // we may need a rewrite of the encoded path.
587 tmp.pathname = cleanupPathName(tmp.pathname, true);
588 if(tmp.pathname.at(0) != '/')
595 if( opts.has(ViewOptions::WITH_PATH_PARAMS))
597 tmp.pathparams = getPathParams();
598 if( !tmp.pathparams.empty())
600 url += ";" + tmp.pathparams;
602 else if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
608 else if( opts.has(ViewOptions::EMPTY_PATH_NAME)
609 && url.find("/") != std::string::npos)
612 if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
619 if( opts.has(ViewOptions::WITH_QUERY_STR))
621 const std::string & querystr { getQueryString( opts ) }; // full or safe depending on opts
622 if( !querystr.empty() )
624 url += "?" + querystr;
626 else if( opts.has(ViewOptions::EMPTY_QUERY_STR))
632 if( opts.has(ViewOptions::WITH_FRAGMENT))
634 tmp.fragment = getFragment(zypp::url::E_ENCODED);
635 if( !tmp.fragment.empty())
637 url += "#" + tmp.fragment;
639 else if( opts.has(ViewOptions::EMPTY_FRAGMENT))
649 // ---------------------------------------------------------------
651 UrlBase::getScheme() const
653 return m_data->scheme;
657 // ---------------------------------------------------------------
659 UrlBase::getAuthority() const
662 if( !getHost(zypp::url::E_ENCODED).empty())
664 if( !getUsername(zypp::url::E_ENCODED).empty())
666 str = getUsername(zypp::url::E_ENCODED);
667 if( !getPassword(zypp::url::E_ENCODED).empty())
669 str += ":" + getPassword(zypp::url::E_ENCODED);
674 str += getHost(zypp::url::E_ENCODED);
675 if( !getPort().empty())
677 str += ":" + getPort();
684 // ---------------------------------------------------------------
686 UrlBase::getPathData() const
688 return getPathName(zypp::url::E_ENCODED) +
689 config("sep_pathparams") +
694 // ---------------------------------------------------------------
696 UrlBase::getQueryString() const
698 return m_data->querystr;
702 UrlBase::getQueryString( const ViewOptions & viewopts_r ) const
704 return m_data->querystr.str( viewopts_r );
707 // ---------------------------------------------------------------
709 UrlBase::getFragment(EEncoding eflag) const
711 if(eflag == zypp::url::E_DECODED)
712 return zypp::url::decode(m_data->fragment);
714 return m_data->fragment;
718 // ---------------------------------------------------------------
720 UrlBase::getUsername(EEncoding eflag) const
722 if(eflag == zypp::url::E_DECODED)
723 return zypp::url::decode(m_data->user);
729 // ---------------------------------------------------------------
731 UrlBase::getPassword(EEncoding eflag) const
733 if(eflag == zypp::url::E_DECODED)
734 return zypp::url::decode(m_data->pass);
740 // ---------------------------------------------------------------
742 UrlBase::getHost(EEncoding eflag) const
744 if(eflag == zypp::url::E_DECODED)
745 return zypp::url::decode(m_data->host);
751 // ---------------------------------------------------------------
753 UrlBase::getPort() const
759 // ---------------------------------------------------------------
761 UrlBase::getPathName(EEncoding eflag) const
763 if(eflag == zypp::url::E_DECODED)
764 return zypp::url::decode(m_data->pathname);
766 return cleanupPathName(m_data->pathname);
770 // ---------------------------------------------------------------
772 UrlBase::getPathParams() const
774 return m_data->pathparams;
778 // ---------------------------------------------------------------
780 UrlBase::getPathParamsVec() const
782 zypp::url::ParamVec pvec;
783 if( config("psep_pathparam").empty())
785 pvec.push_back(getPathParams());
792 config("psep_pathparam")
799 // ---------------------------------------------------------------
801 UrlBase::getPathParamsMap(EEncoding eflag) const
803 if( config("psep_pathparam").empty() ||
804 config("vsep_pathparam").empty())
806 ZYPP_THROW(UrlNotSupportedException(
807 "Path parameter parsing not supported for this URL"
810 zypp::url::ParamMap pmap;
814 config("psep_pathparam"),
815 config("vsep_pathparam"),
822 // ---------------------------------------------------------------
824 UrlBase::getPathParam(const std::string ¶m, EEncoding eflag) const
826 zypp::url::ParamMap pmap( getPathParamsMap( eflag));
827 zypp::url::ParamMap::const_iterator i( pmap.find(param));
829 return i != pmap.end() ? i->second : std::string();
833 // ---------------------------------------------------------------
835 UrlBase::getQueryStringVec() const
837 zypp::url::ParamVec pvec;
838 if( config("psep_querystr").empty())
840 pvec.push_back(getQueryString());
847 config("psep_querystr")
854 // ---------------------------------------------------------------
856 UrlBase::getQueryStringMap(EEncoding eflag) const
858 if( config("psep_querystr").empty() ||
859 config("vsep_querystr").empty())
861 ZYPP_THROW(UrlNotSupportedException(
862 _("Query string parsing not supported for this URL")
865 zypp::url::ParamMap pmap;
869 config("psep_querystr"),
870 config("vsep_querystr"),
877 // ---------------------------------------------------------------
879 UrlBase::getQueryParam(const std::string ¶m, EEncoding eflag) const
881 zypp::url::ParamMap pmap( getQueryStringMap( eflag));
882 zypp::url::ParamMap::const_iterator i( pmap.find(param));
884 return i != pmap.end() ? i->second : std::string();
888 // ---------------------------------------------------------------
890 UrlBase::setScheme(const std::string &scheme)
892 if( isValidScheme(scheme))
894 m_data->scheme = str::toLower(scheme);
899 ZYPP_THROW(UrlBadComponentException(
900 _("Url scheme is a required component")
905 ZYPP_THROW(UrlBadComponentException(
906 str::form(_("Invalid Url scheme '%s'"), scheme.c_str())
912 // ---------------------------------------------------------------
914 UrlBase::setAuthority(const std::string &authority)
916 std::string s = authority;
917 std::string::size_type p,q;
919 std::string username, password, host, port;
921 if ((p=s.find('@')) != std::string::npos)
924 if (q != std::string::npos && q < p)
926 setUsername(s.substr(0, q), zypp::url::E_ENCODED);
927 setPassword(s.substr(q+1, p-q-1), zypp::url::E_ENCODED);
930 setUsername(s.substr(0, p), zypp::url::E_ENCODED);
933 if ((p = s.rfind(':')) != std::string::npos && ( (q = s.rfind(']')) == std::string::npos || q < p) )
935 setHost(s.substr(0, p));
936 setPort(s.substr(p+1));
942 // ---------------------------------------------------------------
944 UrlBase::setPathData(const std::string &pathdata)
946 size_t pos = std::string::npos;
947 std::string sep(config("sep_pathparams"));
950 pos = pathdata.find(sep);
952 if( pos != std::string::npos)
954 setPathName(pathdata.substr(0, pos),
955 zypp::url::E_ENCODED);
956 setPathParams(pathdata.substr(pos + 1));
960 setPathName(pathdata,
961 zypp::url::E_ENCODED);
967 // ---------------------------------------------------------------
969 UrlBase::setQueryString(const std::string &querystr)
971 if( querystr.empty())
973 m_data->querystr = querystr;
977 checkUrlData(querystr, "query string", config("rx_querystr"));
979 m_data->querystr = querystr;
984 // ---------------------------------------------------------------
986 UrlBase::setFragment(const std::string &fragment,
989 if( fragment.empty())
991 m_data->fragment = fragment;
995 if(eflag == zypp::url::E_ENCODED)
997 checkUrlData(fragment, "fragment", config("rx_fragment"));
999 m_data->fragment = fragment;
1003 m_data->fragment = zypp::url::encode(
1004 fragment, config("safe_fragment")
1011 // ---------------------------------------------------------------
1013 UrlBase::setUsername(const std::string &user,
1018 m_data->user = user;
1022 if( config("with_authority") != "y")
1024 ZYPP_THROW(UrlNotAllowedException(
1025 _("Url scheme does not allow a username")
1029 if(eflag == zypp::url::E_ENCODED)
1031 checkUrlData(user, "username", config("rx_username"));
1033 m_data->user = user;
1037 m_data->user = zypp::url::encode(
1038 user, config("safe_username")
1045 // ---------------------------------------------------------------
1047 UrlBase::setPassword(const std::string &pass,
1052 m_data->pass = pass;
1056 if( config("with_authority") != "y")
1058 ZYPP_THROW(UrlNotAllowedException(
1059 _("Url scheme does not allow a password")
1063 if(eflag == zypp::url::E_ENCODED)
1065 checkUrlData(pass, "password", config("rx_password"), false);
1067 m_data->pass = pass;
1071 m_data->pass = zypp::url::encode(
1072 pass, config("safe_password")
1079 // ---------------------------------------------------------------
1081 UrlBase::setHost(const std::string &host)
1085 if(config("require_host") == "m")
1087 ZYPP_THROW(UrlNotAllowedException(
1088 _("Url scheme requires a host component")
1091 m_data->host = host;
1095 if( config("with_authority") != "y")
1097 ZYPP_THROW(UrlNotAllowedException(
1098 _("Url scheme does not allow a host component")
1102 if( isValidHost(host))
1106 // always decode in case isValidHost()
1107 // is reimplemented and supports also
1108 // the [v ... ] notation.
1109 if( host.at(0) == '[')
1111 temp = str::toUpper(zypp::url::decode(host));
1115 temp = str::toLower(zypp::url::decode(host));
1118 m_data->host = zypp::url::encode(
1119 temp, config("safe_hostname")
1124 ZYPP_THROW(UrlBadComponentException(
1125 str::form(_("Invalid host component '%s'"), host.c_str())
1132 // ---------------------------------------------------------------
1134 UrlBase::setPort(const std::string &port)
1138 m_data->port = port;
1142 if( config("with_authority") != "y" ||
1143 config("with_port") != "y")
1145 ZYPP_THROW(UrlNotAllowedException(
1146 _("Url scheme does not allow a port")
1150 if( isValidPort(port))
1152 m_data->port = port;
1156 ZYPP_THROW(UrlBadComponentException(
1157 str::form(_("Invalid port component '%s'"), port.c_str())
1164 // ---------------------------------------------------------------
1166 UrlBase::setPathName(const std::string &path,
1171 if(config("require_pathname") == "m")
1173 ZYPP_THROW(UrlNotAllowedException(
1174 _("Url scheme requires path name")
1177 m_data->pathname = path;
1181 if(eflag == zypp::url::E_ENCODED)
1183 checkUrlData(path, "path name", config("rx_pathname"));
1185 if( !getHost(zypp::url::E_ENCODED).empty())
1187 // has to begin with a "/". For consistency with
1188 // setPathName while the host is empty, we allow
1189 // it in encoded ("%2f") form - cleanupPathName()
1190 // will fix / decode the first slash if needed.
1191 if(!(path.at(0) == '/' || (path.size() >= 3 &&
1192 str::toLower(path.substr(0, 3)) == "%2f")))
1194 ZYPP_THROW(UrlNotAllowedException(
1195 _("Relative path not allowed if authority exists")
1200 m_data->pathname = cleanupPathName(path);
1202 else // zypp::url::E_DECODED
1204 if( !getHost(zypp::url::E_ENCODED).empty())
1206 if(path.at(0) != '/')
1208 ZYPP_THROW(UrlNotAllowedException(
1209 _("Relative path not allowed if authority exists")
1214 m_data->pathname = cleanupPathName(
1216 path, config("safe_pathname")
1224 // ---------------------------------------------------------------
1226 UrlBase::setPathParams(const std::string ¶ms)
1230 m_data->pathparams = params;
1234 checkUrlData(params, "path parameters", config("rx_pathparams"));
1236 m_data->pathparams = params;
1241 // ---------------------------------------------------------------
1243 UrlBase::setPathParamsVec(const zypp::url::ParamVec &pvec)
1248 config("psep_pathparam")
1254 // ---------------------------------------------------------------
1256 UrlBase::setPathParamsMap(const zypp::url::ParamMap &pmap)
1258 if( config("psep_pathparam").empty() ||
1259 config("vsep_pathparam").empty())
1261 ZYPP_THROW(UrlNotSupportedException(
1262 "Path Parameter parsing not supported for this URL"
1268 config("psep_pathparam"),
1269 config("vsep_pathparam"),
1270 config("safe_pathparams")
1276 // ---------------------------------------------------------------
1278 UrlBase::setPathParam(const std::string ¶m, const std::string &value)
1280 zypp::url::ParamMap pmap( getPathParamsMap(zypp::url::E_DECODED));
1281 pmap[param] = value;
1282 setPathParamsMap(pmap);
1286 // ---------------------------------------------------------------
1288 UrlBase::setQueryStringVec(const zypp::url::ParamVec &pvec)
1293 config("psep_querystr")
1299 // ---------------------------------------------------------------
1301 UrlBase::setQueryStringMap(const zypp::url::ParamMap &pmap)
1303 if( config("psep_querystr").empty() ||
1304 config("vsep_querystr").empty())
1306 ZYPP_THROW(UrlNotSupportedException(
1307 _("Query string parsing not supported for this URL")
1313 config("psep_querystr"),
1314 config("vsep_querystr"),
1315 config("safe_querystr")
1320 // ---------------------------------------------------------------
1322 UrlBase::setQueryParam(const std::string ¶m, const std::string &value)
1324 zypp::url::ParamMap pmap( getQueryStringMap(zypp::url::E_DECODED));
1325 pmap[param] = value;
1326 setQueryStringMap(pmap);
1329 // ---------------------------------------------------------------
1331 UrlBase::delQueryParam(const std::string ¶m)
1333 zypp::url::ParamMap pmap( getQueryStringMap(zypp::url::E_DECODED));
1335 setQueryStringMap(pmap);
1339 // ---------------------------------------------------------------
1341 UrlBase::cleanupPathName(const std::string &path) const
1343 bool authority = !getHost(zypp::url::E_ENCODED).empty();
1344 return cleanupPathName(path, authority);
1347 // ---------------------------------------------------------------
1349 UrlBase::cleanupPathName(const std::string &path, bool authority) const
1351 std::string copy( path);
1353 // decode the first slash if it is encoded ...
1354 if(copy.size() >= 3 && copy.at(0) != '/' &&
1355 str::toLower(copy.substr(0, 3)) == "%2f")
1357 copy.replace(0, 3, "/");
1360 // if path begins with a double slash ("//"); encode the second
1361 // slash [minimal and IMO sufficient] before the first path
1362 // segment, to fulfill the path-absolute rule of RFC 3986
1363 // disallowing a "//" if no authority is present.
1367 // rewrite of "//" to "/%2f" not required, use config
1369 if(config("path_encode_slash2") == "y")
1371 // rewrite "//" ==> "/%2f"
1372 if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
1374 copy.replace(1, 1, "%2F");
1379 // rewrite "/%2f" ==> "//"
1380 if(copy.size() >= 4 && copy.at(0) == '/' &&
1381 str::toLower(copy.substr(1, 4)) == "%2f")
1383 copy.replace(1, 4, "/");
1389 // rewrite of "//" to "/%2f" is required (no authority)
1390 if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
1392 copy.replace(1, 1, "%2F");
1399 // ---------------------------------------------------------------
1401 UrlBase::isValidHost(const std::string &host) const
1405 str::regex regx(RX_VALID_HOSTIPV6);
1406 if( str::regex_match(host, regx))
1409 std::string temp( host.substr(1, host.size()-2));
1411 return inet_pton(AF_INET6, temp.c_str(), &ip) > 0;
1415 // matches also IPv4 dotted-decimal adresses...
1416 std::string temp( zypp::url::decode(host));
1417 str::regex regx(RX_VALID_HOSTNAME);
1418 return str::regex_match(temp, regx);
1428 // ---------------------------------------------------------------
1430 UrlBase::isValidPort(const std::string &port) const
1434 str::regex regx(RX_VALID_PORT);
1435 if( str::regex_match(port, regx))
1437 long pnum = str::strtonum<long>(port);
1438 return ( pnum >= 1 && pnum <= USHRT_MAX);
1447 //////////////////////////////////////////////////////////////////
1449 ////////////////////////////////////////////////////////////////////
1451 ////////////////////////////////////////////////////////////////////
1453 //////////////////////////////////////////////////////////////////////
1455 ** vim: set ts=2 sts=2 sw=2 ai et: