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