libzypp  17.25.5
UrlBase.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
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>
17 
18 #include <stdexcept>
19 #include <climits>
20 #include <errno.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <arpa/inet.h>
24 
25 #include <iostream>
26 
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"
30 
31 // ---------------------------------------------------------------
32 /*
33 ** authority = //[user [:password] @ ] host [:port]
34 **
35 ** host = hostname | IPv4 | "[" IPv6-IP "]" | "[v...]"
36 */
37 #define RX_VALID_SCHEME "^[" a_zA_Z "][" a_zA_Z "0-9\\.+-]*$"
38 
39 #define RX_VALID_PORT "^[0-9]{1,5}$"
40 
41 #define RX_VALID_HOSTNAME "^[[:alnum:]${_}]+([\\.-][[:alnum:]${_}]+)*$"
42 
43 #define RX_VALID_HOSTIPV4 \
44  "^([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})$"
45 
46 #define RX_VALID_HOSTIPV6 \
47  "^\\[[:a-fA-F0-9]+(:[0-9]{1,3}(\\.[0-9]{1,3}){3})?\\]$"
48 
49 
51 namespace zypp
52 {
53 
55  namespace url
56  {
57 
58 
59  // ---------------------------------------------------------------
60  /*
61  ** URL asString() view option constants:
62  */
63  const ViewOption ViewOption::WITH_SCHEME = 0x0001;
66  const ViewOption ViewOption::WITH_HOST = 0x0008;
67  const ViewOption ViewOption::WITH_PORT = 0x0010;
77  const ViewOption ViewOption::DEFAULTS = 0x07bb;
78 
80  /*
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;
91  */
92 
93  // ---------------------------------------------------------------
95  : opt(0x07bb)
96  {}
97 
98  // ---------------------------------------------------------------
100  : opt(option)
101  {}
102 
103 
104  // ---------------------------------------------------------------
105  /*
106  ** Behaviour configuration variables.
107  */
108  typedef std::map< std::string, std::string > UrlConfig;
109 
110 
111  // ---------------------------------------------------------------
112 
121  {
122  public:
124  {}
125 
126  SafeQuerystr( std::string rhs )
127  { _assign( std::move(rhs) ); }
128 
129  SafeQuerystr & operator=( std::string rhs )
130  { _assign( std::move(rhs) ); return *this; }
131 
132 
133  operator const std::string &() const
134  { return str(); }
135 
136  const std::string & str() const
137  { return fullStr(); }
138 
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(); }
141 
142  const std::string & fullStr() const
143  { return _fullQuerytsr; }
144 
145  const std::string & safeStr() const
146  { return _safeQuerytsr ? _safeQuerytsr.value() : _fullQuerytsr; }
147 
148  private:
149  void _assign( std::string && rhs )
150  {
151  _fullQuerytsr = std::move(rhs);
152 
153  static constexpr std::string_view tag { "proxypass=" };
154  if ( _fullQuerytsr.find( tag ) != std::string::npos )
155  {
156  std::string safe;
157  strv::split( _fullQuerytsr, "&", [&safe]( std::string_view val ) {
158  if ( val.substr( 0, tag.size() ) != tag ) {
159  if ( ! safe.empty() )
160  safe += "&";
161  safe += val;
162  }
163  });
164  _safeQuerytsr = std::move(safe);
165  }
166  else
167  _safeQuerytsr = std::nullopt;
168  }
169  private:
170  std::string _fullQuerytsr;
171  std::optional<std::string> _safeQuerytsr;
172  };
173 
178  {
179  public:
181  {}
182 
183  UrlBaseData(const UrlConfig &conf)
184  : config(conf)
185  {}
186 
189 
190  std::string scheme;
191  std::string user;
192  std::string pass;
193  std::string host;
194  std::string port;
195  std::string pathname;
196  std::string pathparams;
198  std::string fragment;
199  };
200 
201 
202  // ---------------------------------------------------------------
203  /*
204  ** Anonymous/internal utility namespace:
205  */
206  namespace // anonymous
207  {
208 
209  // -------------------------------------------------------------
210  inline void
211  checkUrlData(const std::string &data,
212  const std::string &name,
213  const std::string &regx,
214  bool show=true)
215  {
216  if( regx.empty() || regx == "^$")
217  {
219  str::form(_("Url scheme does not allow a %s"), name.c_str())
220  ));
221  }
222  else
223  {
224  bool valid = false;
225  try
226  {
227  str::regex rex(regx);
228  valid = str::regex_match(data, rex);
229  }
230  catch( ... )
231  {}
232 
233  if( !valid)
234  {
235  if( show)
236  {
238  str::form(_("Invalid %s component '%s'"),
239  name.c_str(), data.c_str())
240  ));
241  }
242  else
243  {
245  str::form(_("Invalid %s component"), name.c_str())
246  ));
247  }
248  }
249  }
250  }
251 
252  } // namespace
253 
254 
255  // ---------------------------------------------------------------
257  {
258  delete m_data;
259  m_data = NULL;
260  }
261 
262 
263  // ---------------------------------------------------------------
265  : m_data( new UrlBaseData())
266  {
267  configure();
268  }
269 
270 
271  // ---------------------------------------------------------------
273  : m_data( new UrlBaseData( *(url.m_data)))
274  {
275  }
276 
277 
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())
285  {
286  configure();
287  init(scheme, authority, pathdata, querystr, fragment);
288  }
289 
290 
291  // ---------------------------------------------------------------
292  void
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)
298  {
299  if ( scheme.empty() && *pathdata.c_str() == '/' )
300  setScheme("file");
301  else
302  setScheme(scheme);
303 
304  setAuthority(authority);
305  setPathData(pathdata);
306  setQueryString(querystr);
308  }
309 
310 
311  // ---------------------------------------------------------------
312  void
314  {
315  config("sep_pathparams", ";");
316  config("psep_pathparam", ",");
317  config("vsep_pathparam", "=");
318 
319  config("psep_querystr", "&");
320  config("vsep_querystr", "=");
321 
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", "~!$&'()*+=,:;@/?");
329 
330  // y=yes (allowed)
331  // n=no (disallowed, exception if !empty)
332  config("with_authority", "y");
333  config("with_port", "y");
334 
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");
340 
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");
344 
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})+$");
347 
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})+$");
350 
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})+$");
353  }
354 
355 
356  // ---------------------------------------------------------------
357  void
358  UrlBase::config(const std::string &opt, const std::string &val)
359  {
360  m_data->config[opt] = val;
361  }
362 
363 
364  // ---------------------------------------------------------------
365  std::string
366  UrlBase::config(const std::string &opt) const
367  {
368  UrlConfig::const_iterator v( m_data->config.find(opt));
369  if( v != m_data->config.end())
370  return v->second;
371  else
372  return std::string();
373  }
374 
375 
376  // ---------------------------------------------------------------
379  {
380  return m_data->vopts;
381  }
382 
383 
384  // ---------------------------------------------------------------
385  void
387  {
388  m_data->vopts = vopts;
389  }
390 
391 
392  // ---------------------------------------------------------------
393  void
395  {
398  *m_data = UrlBaseData();
399  m_data->config = config;
400  m_data->vopts = vopts;
401  }
402 
403 
404  // ---------------------------------------------------------------
405  UrlBase *
407  {
408  return new UrlBase(*this);
409  }
410 
411 
412  // ---------------------------------------------------------------
415  {
416  return UrlSchemes();
417  }
418 
419 
420  // ---------------------------------------------------------------
421  bool
422  UrlBase::isKnownScheme(const std::string &scheme) const
423  {
424  std::string lscheme( str::toLower(scheme));
425  UrlSchemes schemes( getKnownSchemes());
426  UrlSchemes::const_iterator s;
427 
428  for(s=schemes.begin(); s!=schemes.end(); ++s)
429  {
430  if( lscheme == str::toLower(*s))
431  return true;
432  }
433  return false;
434  }
435 
436 
437  // ---------------------------------------------------------------
438  bool
439  UrlBase::isValidScheme(const std::string &scheme) const
440  {
441  bool valid = false;
442  try
443  {
445  valid = str::regex_match(scheme, rex);
446  }
447  catch( ... )
448  {}
449 
450  if(valid)
451  {
452  std::string lscheme( str::toLower(scheme));
453  UrlSchemes schemes( getKnownSchemes());
454 
455  if( schemes.empty())
456  return true;
457 
458  UrlSchemes::const_iterator s;
459  for(s=schemes.begin(); s!=schemes.end(); ++s)
460  {
461  if( lscheme == str::toLower(*s))
462  return true;
463  }
464  }
465  return false;
466  }
467 
468 
469  // ---------------------------------------------------------------
470  bool
472  {
473  /*
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.
478  */
479  if( getScheme().empty())
480  return false;
481 
482  std::string host( getHost(zypp::url::E_ENCODED));
483  if( host.empty() && config("require_host") != "n")
484  return false;
485 
486  std::string path( getPathName(zypp::url::E_ENCODED));
487  if( path.empty() && config("require_pathname") != "n")
488  return false;
489 
490  /*
491  ** path has to begin with "/" if authority avaliable
492  ** if host is set after the pathname, we can't throw
493  */
494  if( !host.empty() && !path.empty() && path.at(0) != '/')
495  return false;
496 
497  return true;
498  }
499 
500 
501  // ---------------------------------------------------------------
502  std::string
504  {
505  return asString(getViewOptions());
506  }
507 
508  std::string UrlBase::asString1050625() const
509  {
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.
513  }
514 
515  // ---------------------------------------------------------------
516  std::string
518  {
519  std::string url;
520  UrlBaseData tmp;
521 
522  if( opts.has(ViewOptions::WITH_SCHEME))
523  {
524  tmp.scheme = getScheme();
525  if( !tmp.scheme.empty())
526  {
527  url += tmp.scheme + ":";
528 
529  if( opts.has(ViewOptions::WITH_HOST))
530  {
532  if( !tmp.host.empty())
533  {
534  url += "//";
535 
537  {
539  if( !tmp.user.empty())
540  {
541  url += tmp.user;
542 
544  {
546  if( !tmp.pass.empty())
547  {
548  url += ":" + tmp.pass;
549  }
550  }
551  url += "@";
552  }
553  }
554 
555  url += tmp.host;
556 
557  if( opts.has(ViewOptions::WITH_PORT))
558  {
559  tmp.port = getPort();
560  if( !tmp.port.empty())
561  {
562  url += ":" + tmp.port;
563  }
564  }
565  }
566  else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
567  {
568  url += "//";
569  }
570  }
571  else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
572  {
573  url += "//";
574  }
575  }
576  }
577 
579  {
581  if( !tmp.pathname.empty())
582  {
583  if(url.find("/") != std::string::npos)
584  {
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) != '/')
589  {
590  url += "/";
591  }
592  }
593  url += tmp.pathname;
594 
596  {
597  tmp.pathparams = getPathParams();
598  if( !tmp.pathparams.empty())
599  {
600  url += ";" + tmp.pathparams;
601  }
602  else if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
603  {
604  url += ";";
605  }
606  }
607  }
608  else if( opts.has(ViewOptions::EMPTY_PATH_NAME)
609  && url.find("/") != std::string::npos)
610  {
611  url += "/";
613  {
614  url += ";";
615  }
616  }
617  }
618 
620  {
621  const std::string & querystr { getQueryString( opts ) }; // full or safe depending on opts
622  if( !querystr.empty() )
623  {
624  url += "?" + querystr;
625  }
626  else if( opts.has(ViewOptions::EMPTY_QUERY_STR))
627  {
628  url += "?";
629  }
630  }
631 
633  {
635  if( !tmp.fragment.empty())
636  {
637  url += "#" + tmp.fragment;
638  }
639  else if( opts.has(ViewOptions::EMPTY_FRAGMENT))
640  {
641  url += "#";
642  }
643  }
644 
645  return url;
646  }
647 
648 
649  // ---------------------------------------------------------------
650  std::string
652  {
653  return m_data->scheme;
654  }
655 
656 
657  // ---------------------------------------------------------------
658  std::string
660  {
661  std::string str;
662  if( !getHost(zypp::url::E_ENCODED).empty())
663  {
664  if( !getUsername(zypp::url::E_ENCODED).empty())
665  {
667  if( !getPassword(zypp::url::E_ENCODED).empty())
668  {
670  }
671  str += "@";
672  }
673 
675  if( !getPort().empty())
676  {
677  str += ":" + getPort();
678  }
679  }
680  return str;
681  }
682 
683 
684  // ---------------------------------------------------------------
685  std::string
687  {
689  config("sep_pathparams") +
690  getPathParams();
691  }
692 
693 
694  // ---------------------------------------------------------------
695  std::string
697  {
698  return m_data->querystr;
699  }
700 
701  std::string
702  UrlBase::getQueryString( const ViewOptions & viewopts_r ) const
703  {
704  return m_data->querystr.str( viewopts_r );
705  }
706 
707  // ---------------------------------------------------------------
708  std::string
710  {
711  if(eflag == zypp::url::E_DECODED)
713  else
714  return m_data->fragment;
715  }
716 
717 
718  // ---------------------------------------------------------------
719  std::string
721  {
722  if(eflag == zypp::url::E_DECODED)
723  return zypp::url::decode(m_data->user);
724  else
725  return m_data->user;
726  }
727 
728 
729  // ---------------------------------------------------------------
730  std::string
732  {
733  if(eflag == zypp::url::E_DECODED)
734  return zypp::url::decode(m_data->pass);
735  else
736  return m_data->pass;
737  }
738 
739 
740  // ---------------------------------------------------------------
741  std::string
743  {
744  if(eflag == zypp::url::E_DECODED)
745  return zypp::url::decode(m_data->host);
746  else
747  return m_data->host;
748  }
749 
750 
751  // ---------------------------------------------------------------
752  std::string
754  {
755  return m_data->port;
756  }
757 
758 
759  // ---------------------------------------------------------------
760  std::string
762  {
763  if(eflag == zypp::url::E_DECODED)
765  else
767  }
768 
769 
770  // ---------------------------------------------------------------
771  std::string
773  {
774  return m_data->pathparams;
775  }
776 
777 
778  // ---------------------------------------------------------------
781  {
782  zypp::url::ParamVec pvec;
783  if( config("psep_pathparam").empty())
784  {
785  pvec.push_back(getPathParams());
786  }
787  else
788  {
790  pvec,
791  getPathParams(),
792  config("psep_pathparam")
793  );
794  }
795  return pvec;
796  }
797 
798 
799  // ---------------------------------------------------------------
802  {
803  if( config("psep_pathparam").empty() ||
804  config("vsep_pathparam").empty())
805  {
807  "Path parameter parsing not supported for this URL"
808  ));
809  }
810  zypp::url::ParamMap pmap;
812  pmap,
813  getPathParams(),
814  config("psep_pathparam"),
815  config("vsep_pathparam"),
816  eflag
817  );
818  return pmap;
819  }
820 
821 
822  // ---------------------------------------------------------------
823  std::string
824  UrlBase::getPathParam(const std::string &param, EEncoding eflag) const
825  {
826  zypp::url::ParamMap pmap( getPathParamsMap( eflag));
827  zypp::url::ParamMap::const_iterator i( pmap.find(param));
828 
829  return i != pmap.end() ? i->second : std::string();
830  }
831 
832 
833  // ---------------------------------------------------------------
836  {
837  zypp::url::ParamVec pvec;
838  if( config("psep_querystr").empty())
839  {
840  pvec.push_back(getQueryString());
841  }
842  else
843  {
845  pvec,
846  getQueryString(),
847  config("psep_querystr")
848  );
849  }
850  return pvec;
851  }
852 
853 
854  // ---------------------------------------------------------------
857  {
858  if( config("psep_querystr").empty() ||
859  config("vsep_querystr").empty())
860  {
862  _("Query string parsing not supported for this URL")
863  ));
864  }
865  zypp::url::ParamMap pmap;
867  pmap,
868  getQueryString(),
869  config("psep_querystr"),
870  config("vsep_querystr"),
871  eflag
872  );
873  return pmap;
874  }
875 
876 
877  // ---------------------------------------------------------------
878  std::string
879  UrlBase::getQueryParam(const std::string &param, EEncoding eflag) const
880  {
881  zypp::url::ParamMap pmap( getQueryStringMap( eflag));
882  zypp::url::ParamMap::const_iterator i( pmap.find(param));
883 
884  return i != pmap.end() ? i->second : std::string();
885  }
886 
887 
888  // ---------------------------------------------------------------
889  void
890  UrlBase::setScheme(const std::string &scheme)
891  {
892  if( isValidScheme(scheme))
893  {
894  m_data->scheme = str::toLower(scheme);
895  }
896  else
897  if( scheme.empty())
898  {
900  _("Url scheme is a required component")
901  ));
902  }
903  else
904  {
906  str::form(_("Invalid Url scheme '%s'"), scheme.c_str())
907  ));
908  }
909  }
910 
911 
912  // ---------------------------------------------------------------
913  void
914  UrlBase::setAuthority(const std::string &authority)
915  {
916  std::string s = authority;
918 
919  std::string username, password, host, port;
920 
921  if ((p=s.find('@')) != std::string::npos)
922  {
923  q = s.find(':');
924  if (q != std::string::npos && q < p)
925  {
926  setUsername(s.substr(0, q), zypp::url::E_ENCODED);
927  setPassword(s.substr(q+1, p-q-1), zypp::url::E_ENCODED);
928  }
929  else
930  setUsername(s.substr(0, p), zypp::url::E_ENCODED);
931  s = s.substr(p+1);
932  }
933  if ((p = s.rfind(':')) != std::string::npos && ( (q = s.rfind(']')) == std::string::npos || q < p) )
934  {
935  setHost(s.substr(0, p));
936  setPort(s.substr(p+1));
937  }
938  else
939  setHost(s);
940  }
941 
942  // ---------------------------------------------------------------
943  void
944  UrlBase::setPathData(const std::string &pathdata)
945  {
946  size_t pos = std::string::npos;
947  std::string sep(config("sep_pathparams"));
948 
949  if( !sep.empty())
950  pos = pathdata.find(sep);
951 
952  if( pos != std::string::npos)
953  {
954  setPathName(pathdata.substr(0, pos),
956  setPathParams(pathdata.substr(pos + 1));
957  }
958  else
959  {
960  setPathName(pathdata,
962  setPathParams("");
963  }
964  }
965 
966 
967  // ---------------------------------------------------------------
968  void
969  UrlBase::setQueryString(const std::string &querystr)
970  {
971  if( querystr.empty())
972  {
973  m_data->querystr = querystr;
974  }
975  else
976  {
977  checkUrlData(querystr, "query string", config("rx_querystr"));
978 
979  m_data->querystr = querystr;
980  }
981  }
982 
983 
984  // ---------------------------------------------------------------
985  void
986  UrlBase::setFragment(const std::string &fragment,
987  EEncoding eflag)
988  {
989  if( fragment.empty())
990  {
991  m_data->fragment = fragment;
992  }
993  else
994  {
995  if(eflag == zypp::url::E_ENCODED)
996  {
997  checkUrlData(fragment, "fragment", config("rx_fragment"));
998 
999  m_data->fragment = fragment;
1000  }
1001  else
1002  {
1004  fragment, config("safe_fragment")
1005  );
1006  }
1007  }
1008  }
1009 
1010 
1011  // ---------------------------------------------------------------
1012  void
1013  UrlBase::setUsername(const std::string &user,
1014  EEncoding eflag)
1015  {
1016  if( user.empty())
1017  {
1018  m_data->user = user;
1019  }
1020  else
1021  {
1022  if( config("with_authority") != "y")
1023  {
1025  _("Url scheme does not allow a username")
1026  ));
1027  }
1028 
1029  if(eflag == zypp::url::E_ENCODED)
1030  {
1031  checkUrlData(user, "username", config("rx_username"));
1032 
1033  m_data->user = user;
1034  }
1035  else
1036  {
1038  user, config("safe_username")
1039  );
1040  }
1041  }
1042  }
1043 
1044 
1045  // ---------------------------------------------------------------
1046  void
1047  UrlBase::setPassword(const std::string &pass,
1048  EEncoding eflag)
1049  {
1050  if( pass.empty())
1051  {
1052  m_data->pass = pass;
1053  }
1054  else
1055  {
1056  if( config("with_authority") != "y")
1057  {
1059  _("Url scheme does not allow a password")
1060  ));
1061  }
1062 
1063  if(eflag == zypp::url::E_ENCODED)
1064  {
1065  checkUrlData(pass, "password", config("rx_password"), false);
1066 
1067  m_data->pass = pass;
1068  }
1069  else
1070  {
1072  pass, config("safe_password")
1073  );
1074  }
1075  }
1076  }
1077 
1078 
1079  // ---------------------------------------------------------------
1080  void
1081  UrlBase::setHost(const std::string &host)
1082  {
1083  if( host.empty())
1084  {
1085  if(config("require_host") == "m")
1086  {
1088  _("Url scheme requires a host component")
1089  ));
1090  }
1091  m_data->host = host;
1092  }
1093  else
1094  {
1095  if( config("with_authority") != "y")
1096  {
1098  _("Url scheme does not allow a host component")
1099  ));
1100  }
1101 
1102  if( isValidHost(host))
1103  {
1104  std::string temp;
1105 
1106  // always decode in case isValidHost()
1107  // is reimplemented and supports also
1108  // the [v ... ] notation.
1109  if( host.at(0) == '[')
1110  {
1111  temp = str::toUpper(zypp::url::decode(host));
1112  }
1113  else
1114  {
1115  temp = str::toLower(zypp::url::decode(host));
1116  }
1117 
1119  temp, config("safe_hostname")
1120  );
1121  }
1122  else
1123  {
1125  str::form(_("Invalid host component '%s'"), host.c_str())
1126  ));
1127  }
1128  }
1129  }
1130 
1131 
1132  // ---------------------------------------------------------------
1133  void
1134  UrlBase::setPort(const std::string &port)
1135  {
1136  if( port.empty())
1137  {
1138  m_data->port = port;
1139  }
1140  else
1141  {
1142  if( config("with_authority") != "y" ||
1143  config("with_port") != "y")
1144  {
1146  _("Url scheme does not allow a port")
1147  ));
1148  }
1149 
1150  if( isValidPort(port))
1151  {
1152  m_data->port = port;
1153  }
1154  else
1155  {
1157  str::form(_("Invalid port component '%s'"), port.c_str())
1158  ));
1159  }
1160  }
1161  }
1162 
1163 
1164  // ---------------------------------------------------------------
1165  void
1166  UrlBase::setPathName(const std::string &path,
1167  EEncoding eflag)
1168  {
1169  if( path.empty())
1170  {
1171  if(config("require_pathname") == "m")
1172  {
1174  _("Url scheme requires path name")
1175  ));
1176  }
1177  m_data->pathname = path;
1178  }
1179  else
1180  {
1181  if(eflag == zypp::url::E_ENCODED)
1182  {
1183  checkUrlData(path, "path name", config("rx_pathname"));
1184 
1185  if( !getHost(zypp::url::E_ENCODED).empty())
1186  {
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")))
1193  {
1195  _("Relative path not allowed if authority exists")
1196  ));
1197  }
1198  }
1199 
1200  m_data->pathname = cleanupPathName(path);
1201  }
1202  else // zypp::url::E_DECODED
1203  {
1204  if( !getHost(zypp::url::E_ENCODED).empty())
1205  {
1206  if(path.at(0) != '/')
1207  {
1209  _("Relative path not allowed if authority exists")
1210  ));
1211  }
1212  }
1213 
1216  path, config("safe_pathname")
1217  )
1218  );
1219  }
1220  }
1221  }
1222 
1223 
1224  // ---------------------------------------------------------------
1225  void
1226  UrlBase::setPathParams(const std::string &params)
1227  {
1228  if( params.empty())
1229  {
1230  m_data->pathparams = params;
1231  }
1232  else
1233  {
1234  checkUrlData(params, "path parameters", config("rx_pathparams"));
1235 
1236  m_data->pathparams = params;
1237  }
1238  }
1239 
1240 
1241  // ---------------------------------------------------------------
1242  void
1244  {
1245  setPathParams(
1247  pvec,
1248  config("psep_pathparam")
1249  )
1250  );
1251  }
1252 
1253 
1254  // ---------------------------------------------------------------
1255  void
1257  {
1258  if( config("psep_pathparam").empty() ||
1259  config("vsep_pathparam").empty())
1260  {
1262  "Path Parameter parsing not supported for this URL"
1263  ));
1264  }
1265  setPathParams(
1267  pmap,
1268  config("psep_pathparam"),
1269  config("vsep_pathparam"),
1270  config("safe_pathparams")
1271  )
1272  );
1273  }
1274 
1275 
1276  // ---------------------------------------------------------------
1277  void
1278  UrlBase::setPathParam(const std::string &param, const std::string &value)
1279  {
1281  pmap[param] = value;
1282  setPathParamsMap(pmap);
1283  }
1284 
1285 
1286  // ---------------------------------------------------------------
1287  void
1289  {
1292  pvec,
1293  config("psep_querystr")
1294  )
1295  );
1296  }
1297 
1298 
1299  // ---------------------------------------------------------------
1300  void
1302  {
1303  if( config("psep_querystr").empty() ||
1304  config("vsep_querystr").empty())
1305  {
1307  _("Query string parsing not supported for this URL")
1308  ));
1309  }
1312  pmap,
1313  config("psep_querystr"),
1314  config("vsep_querystr"),
1315  config("safe_querystr")
1316  )
1317  );
1318  }
1319 
1320  // ---------------------------------------------------------------
1321  void
1322  UrlBase::setQueryParam(const std::string &param, const std::string &value)
1323  {
1325  pmap[param] = value;
1326  setQueryStringMap(pmap);
1327  }
1328 
1329  // ---------------------------------------------------------------
1330  void
1331  UrlBase::delQueryParam(const std::string &param)
1332  {
1334  pmap.erase(param);
1335  setQueryStringMap(pmap);
1336  }
1337 
1338 
1339  // ---------------------------------------------------------------
1340  std::string
1341  UrlBase::cleanupPathName(const std::string &path) const
1342  {
1343  bool authority = !getHost(zypp::url::E_ENCODED).empty();
1344  return cleanupPathName(path, authority);
1345  }
1346 
1347  // ---------------------------------------------------------------
1348  std::string
1349  UrlBase::cleanupPathName(const std::string &path, bool authority) const
1350  {
1351  std::string copy( path);
1352 
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")
1356  {
1357  copy.replace(0, 3, "/");
1358  }
1359 
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.
1364  if( authority)
1365  {
1366  //
1367  // rewrite of "//" to "/%2f" not required, use config
1368  //
1369  if(config("path_encode_slash2") == "y")
1370  {
1371  // rewrite "//" ==> "/%2f"
1372  if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
1373  {
1374  copy.replace(1, 1, "%2F");
1375  }
1376  }
1377  else
1378  {
1379  // rewrite "/%2f" ==> "//"
1380  if(copy.size() >= 4 && copy.at(0) == '/' &&
1381  str::toLower(copy.substr(1, 4)) == "%2f")
1382  {
1383  copy.replace(1, 4, "/");
1384  }
1385  }
1386  }
1387  else
1388  {
1389  // rewrite of "//" to "/%2f" is required (no authority)
1390  if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
1391  {
1392  copy.replace(1, 1, "%2F");
1393  }
1394  }
1395  return copy;
1396  }
1397 
1398 
1399  // ---------------------------------------------------------------
1400  bool
1401  UrlBase::isValidHost(const std::string &host) const
1402  {
1403  try
1404  {
1406  if( str::regex_match(host, regx))
1407  {
1408  struct in6_addr ip;
1409  std::string temp( host.substr(1, host.size()-2));
1410 
1411  return inet_pton(AF_INET6, temp.c_str(), &ip) > 0;
1412  }
1413  else
1414  {
1415  // matches also IPv4 dotted-decimal adresses...
1416  std::string temp( zypp::url::decode(host));
1418  return str::regex_match(temp, regx);
1419  }
1420  }
1421  catch( ... )
1422  {}
1423 
1424  return false;
1425  }
1426 
1427 
1428  // ---------------------------------------------------------------
1429  bool
1430  UrlBase::isValidPort(const std::string &port) const
1431  {
1432  try
1433  {
1434  str::regex regx(RX_VALID_PORT);
1435  if( str::regex_match(port, regx))
1436  {
1437  long pnum = str::strtonum<long>(port);
1438  return ( pnum >= 1 && pnum <= USHRT_MAX);
1439  }
1440  }
1441  catch( ... )
1442  {}
1443  return false;
1444  }
1445 
1446 
1448  } // namespace url
1450 
1452 } // namespace zypp
1454 /*
1455 ** vim: set ts=2 sts=2 sw=2 ai et:
1456 */
std::string pathparams
Definition: UrlBase.cc:196
virtual std::string getAuthority() const
Returns the encoded authority component of the URL.
Definition: UrlBase.cc:659
Hide passwords embedded in a querystr,.
Definition: UrlBase.cc:120
Interface to gettext.
static const ViewOption WITH_USERNAME
Option to include username in the URL string.
Definition: UrlBase.h:58
virtual std::string getQueryString() const
Returns the encoded query string component of the URL.
Definition: UrlBase.cc:696
std::vector< std::string > ParamVec
A parameter vector container.
Definition: UrlUtils.h:40
static const ViewOption WITH_FRAGMENT
Option to include fragment string in the URL string.
Definition: UrlBase.h:107
std::map< std::string, std::string > ParamMap
A parameter map container.
Definition: UrlUtils.h:47
Internal data used by UrlBase.
Definition: UrlBase.cc:177
c++17: std::string_view tools
virtual void setQueryParam(const std::string &param, const std::string &value)
Set or add value for the specified query parameter.
Definition: UrlBase.cc:1322
virtual zypp::url::ParamMap getQueryStringMap(EEncoding eflag) const
Returns a string map with query parameter and their values.
Definition: UrlBase.cc:856
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:392
virtual UrlSchemes getKnownSchemes() const
Returns scheme names known by this object.
Definition: UrlBase.cc:414
Regular expression.
Definition: Regex.h:94
std::string asString1050625() const
Definition: UrlBase.cc:508
#define RX_VALID_HOSTNAME
Definition: UrlBase.cc:41
SafeQuerystr & operator=(std::string rhs)
Definition: UrlBase.cc:129
std::vector< std::string > UrlSchemes
Vector of URL scheme names.
Definition: UrlBase.h:251
Flag to request encoded string(s).
Definition: UrlUtils.h:53
virtual ~UrlBase()
Definition: UrlBase.cc:256
ViewOption()
Create instance with default combination of view options.
Definition: UrlBase.cc:94
virtual zypp::url::ParamVec getPathParamsVec() const
Returns a vector with encoded path parameter substrings.
Definition: UrlBase.cc:780
std::string port
Definition: UrlBase.cc:194
virtual void setUsername(const std::string &user, EEncoding eflag)
Set the username in the URL authority.
Definition: UrlBase.cc:1013
virtual std::string getPathName(EEncoding eflag) const
Returns the path name from the URL.
Definition: UrlBase.cc:761
std::string host
Definition: UrlBase.cc:193
SafeQuerystr querystr
Definition: UrlBase.cc:197
static const ViewOption WITH_SCHEME
Option to include scheme name in the URL string.
Definition: UrlBase.h:51
static const ViewOption WITH_HOST
Option to include hostname in the URL string.
Definition: UrlBase.h:74
ViewOptions vopts
Definition: UrlBase.cc:188
virtual void setPathData(const std::string &pathdata)
Set the path data component in the URL.
Definition: UrlBase.cc:944
String related utilities and Regular expression matching.
std::string encode(const std::string &str, const std::string &safe, EEncoding eflag)
Encodes a string using URL percent encoding.
Definition: UrlUtils.cc:32
std::string _fullQuerytsr
Definition: UrlBase.cc:170
UrlBaseData(const UrlConfig &conf)
Definition: UrlBase.cc:183
Url url
Definition: MediaCurl.cc:66
static const ViewOption EMPTY_FRAGMENT
Explicitely include the fragment string separator "#".
Definition: UrlBase.h:165
virtual void setPort(const std::string &port)
Set the port number in the URL authority.
Definition: UrlBase.cc:1134
static const ViewOption hotfix1050625
Definition: UrlBase.h:233
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:36
static const ViewOption WITH_PATH_NAME
Option to include path name in the URL string.
Definition: UrlBase.h:87
Url::asString() view options.
Definition: UrlBase.h:39
void setViewOptions(const ViewOptions &vopts)
Change the view options of the current object.
Definition: UrlBase.cc:386
virtual void setAuthority(const std::string &authority)
Set the authority component in the URL.
Definition: UrlBase.cc:914
virtual void setHost(const std::string &host)
Set the hostname or IP in the URL authority.
Definition: UrlBase.cc:1081
virtual void setPathParams(const std::string &params)
Set the path parameters.
Definition: UrlBase.cc:1226
UrlBaseData * m_data
Definition: UrlBase.h:1081
virtual std::string getPassword(EEncoding eflag) const
Returns the password from the URL authority.
Definition: UrlBase.cc:731
const std::string & safeStr() const
Definition: UrlBase.cc:145
virtual void setPathParamsVec(const zypp::url::ParamVec &pvec)
Set the path parameters.
Definition: UrlBase.cc:1243
virtual std::string getQueryParam(const std::string &param, EEncoding eflag) const
Return the value for the specified query parameter.
Definition: UrlBase.cc:879
#define RX_VALID_PORT
Definition: UrlBase.cc:39
Thrown if a feature e.g.
Definition: UrlException.h:124
std::map< std::string, std::string > UrlConfig
Definition: UrlBase.cc:108
virtual std::string getPathParam(const std::string &param, EEncoding eflag) const
Return the value for the specified path parameter.
Definition: UrlBase.cc:824
virtual void setFragment(const std::string &fragment, EEncoding eflag)
Set the fragment string in the URL.
Definition: UrlBase.cc:986
const std::string & str(const ViewOptions &viewopts_r) const
Definition: UrlBase.cc:139
virtual void setPassword(const std::string &pass, EEncoding eflag)
Set the password in the URL authority.
Definition: UrlBase.cc:1047
virtual std::string getHost(EEncoding eflag) const
Returns the hostname or IP from the URL authority.
Definition: UrlBase.cc:742
virtual std::string getPathParams() const
Returns the encoded path parameters from the URL.
Definition: UrlBase.cc:772
virtual void setQueryStringMap(const zypp::url::ParamMap &qmap)
Set the query parameters.
Definition: UrlBase.cc:1301
virtual std::string getPort() const
Returns the port number from the URL authority.
Definition: UrlBase.cc:753
virtual void init(const std::string &scheme, const std::string &authority, const std::string &pathdata, const std::string &querystr, const std::string &fragment)
Initializes current object with new URL components.
Definition: UrlBase.cc:293
std::string fragment
Definition: UrlBase.cc:198
static const ViewOption EMPTY_QUERY_STR
Explicitely include the query string separator "?".
Definition: UrlBase.h:154
static const ViewOption EMPTY_AUTHORITY
Explicitely include the URL authority separator "//".
Definition: UrlBase.h:121
virtual UrlBase * clone() const
Returns pointer to a copy of the current object.
Definition: UrlBase.cc:406
std::optional< std::string > _safeQuerytsr
Definition: UrlBase.cc:171
ViewOptions getViewOptions() const
Return the view options of the current object.
Definition: UrlBase.cc:378
void split(ParamVec &pvec, const std::string &pstr, const std::string &psep)
Split into a parameter vector.
Definition: UrlUtils.cc:165
virtual std::string getFragment(EEncoding eflag) const
Returns the encoded fragment component of the URL.
Definition: UrlBase.cc:709
static const ViewOption WITH_PATH_PARAMS
Option to include path parameters in the URL string.
Definition: UrlBase.h:95
virtual void setScheme(const std::string &scheme)
Set the scheme name in the URL.
Definition: UrlBase.cc:890
std::string join(const ParamVec &pvec, const std::string &psep)
Join parameter vector to a string.
Definition: UrlUtils.cc:254
#define _(MSG)
Definition: Gettext.h:37
virtual void setQueryString(const std::string &querystr)
Set the query string in the URL.
Definition: UrlBase.cc:969
const std::string & fullStr() const
Definition: UrlBase.cc:142
virtual bool isKnownScheme(const std::string &scheme) const
Returns if scheme name is known to this object.
Definition: UrlBase.cc:422
static const ViewOption EMPTY_PATH_PARAMS
Explicitely include the path parameters separator ";".
Definition: UrlBase.h:143
virtual std::string cleanupPathName(const std::string &path, bool authority) const
Utility method to cleanup an encoded path name.
Definition: UrlBase.cc:1349
std::string toLower(const std::string &s)
Return lowercase version of s.
Definition: String.cc:177
#define RX_VALID_SCHEME
Definition: UrlBase.cc:37
SolvableIdType size_type
Definition: PoolMember.h:126
bool has(const ViewOption &o) const
Check if specified option o is set in the current object.
Definition: UrlBase.h:228
std::ostream & copy(std::istream &from_r, std::ostream &to_r)
Copy istream to ostream.
Definition: IOStream.h:50
std::string config(const std::string &opt) const
Get the value of a UrlBase configuration variable.
Definition: UrlBase.cc:366
virtual void clear()
Clears all data in the object.
Definition: UrlBase.cc:394
virtual void setPathName(const std::string &path, EEncoding eflag)
Set the path name.
Definition: UrlBase.cc:1166
static const ViewOption WITH_QUERY_STR
Option to include query string in the URL string.
Definition: UrlBase.h:101
static const ViewOption EMPTY_PATH_NAME
Explicitely include the "/" path character.
Definition: UrlBase.h:133
std::string pathname
Definition: UrlBase.cc:195
virtual bool isValidPort(const std::string &port) const
Verifies specified port number.
Definition: UrlBase.cc:1430
#define a_zA_Z
Definition: UrlBase.cc:29
static const ViewOption WITH_PASSWORD
Option to include password in the URL string.
Definition: UrlBase.h:67
const std::string & str() const
Definition: UrlBase.cc:136
virtual void configure()
Configures behaviour of the instance.
Definition: UrlBase.cc:313
SafeQuerystr(std::string rhs)
Definition: UrlBase.cc:126
void _assign(std::string &&rhs)
Definition: UrlBase.cc:149
Generic Url base class.
Definition: UrlBase.h:270
virtual void setPathParamsMap(const zypp::url::ParamMap &pmap)
Set the path parameters.
Definition: UrlBase.cc:1256
virtual zypp::url::ParamMap getPathParamsMap(EEncoding eflag) const
Returns a string map with path parameter keys and values.
Definition: UrlBase.cc:801
bool regex_match(const std::string &s, smatch &matches, const regex &regex)
regex ZYPP_STR_REGEX regex ZYPP_STR_REGEX
Definition: Regex.h:70
static const ViewOption DEFAULTS
Default combination of view options.
Definition: UrlBase.h:177
std::string user
Definition: UrlBase.cc:191
virtual bool isValidHost(const std::string &host) const
Verifies specified host or IP.
Definition: UrlBase.cc:1401
virtual zypp::url::ParamVec getQueryStringVec() const
Returns a vector with query string parameter substrings.
Definition: UrlBase.cc:835
#define RX_VALID_HOSTIPV6
Definition: UrlBase.cc:46
virtual std::string getPathData() const
Returns the encoded path component of the URL.
Definition: UrlBase.cc:686
EEncoding
Encoding flags.
Definition: UrlUtils.h:52
static const ViewOption WITH_PORT
Option to include port number in the URL string.
Definition: UrlBase.h:81
virtual void setPathParam(const std::string &param, const std::string &value)
Set or add value for the specified path parameter.
Definition: UrlBase.cc:1278
virtual bool isValidScheme(const std::string &scheme) const
Verifies specified scheme name.
Definition: UrlBase.cc:439
virtual void setQueryStringVec(const zypp::url::ParamVec &qvec)
Set the query parameters.
Definition: UrlBase.cc:1288
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
std::string toUpper(const std::string &s)
Return uppercase version of s.
Definition: String.cc:200
Thrown if a url component is invalid.
Definition: UrlException.h:85
virtual bool isValid() const
Verifies the Url.
Definition: UrlBase.cc:471
virtual std::string asString() const
Returns a default string representation of the Url object.
Definition: UrlBase.cc:503
virtual std::string getUsername(EEncoding eflag) const
Returns the username from the URL authority.
Definition: UrlBase.cc:720
virtual std::string getScheme() const
Returns the scheme name of the URL.
Definition: UrlBase.cc:651
std::string pass
Definition: UrlBase.cc:192
Thrown if scheme does not allow a component.
Definition: UrlException.h:104
std::string scheme
Definition: UrlBase.cc:190
virtual void delQueryParam(const std::string &param)
remove the specified query parameter.
Definition: UrlBase.cc:1331
std::string decode(const std::string &str, bool allowNUL)
Decodes a URL percent encoded string.
Definition: UrlUtils.cc:87
unsigned split(std::string_view line_r, std::string_view sep_r, Trim trim_r, std::function< void(std::string_view)> fnc_r)
Definition: StringV.cc:20
Flag to request decoded string(s).
Definition: UrlUtils.h:54