libzypp  17.35.15
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;
66  const ViewOption ViewOption::WITH_USERNAME = 0x0002;
67  const ViewOption ViewOption::WITH_PASSWORD = 0x0004;
68  const ViewOption ViewOption::WITH_HOST = 0x0008;
69  const ViewOption ViewOption::WITH_PORT = 0x0010;
70  const ViewOption ViewOption::WITH_PATH_NAME = 0x0020;
71  const ViewOption ViewOption::WITH_PATH_PARAMS = 0x0040;
72  const ViewOption ViewOption::WITH_QUERY_STR = 0x0080;
73  const ViewOption ViewOption::WITH_FRAGMENT = 0x0100;
74  const ViewOption ViewOption::EMPTY_AUTHORITY = 0x0200;
75  const ViewOption ViewOption::EMPTY_PATH_NAME = 0x0400;
76  const ViewOption ViewOption::EMPTY_PATH_PARAMS = 0x0800;
77  const ViewOption ViewOption::EMPTY_QUERY_STR = 0x1000;
78  const ViewOption ViewOption::EMPTY_FRAGMENT = 0x2000;
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 
538  if( opts.has(ViewOptions::WITH_USERNAME))
539  {
541  if( !tmp.user.empty())
542  {
543  url += tmp.user;
544 
545  if( opts.has(ViewOptions::WITH_PASSWORD))
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 
580  if( opts.has(ViewOptions::WITH_PATH_NAME))
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 
597  if( opts.has(ViewOptions::WITH_PATH_PARAMS))
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 += "/";
614  if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
615  {
616  url += ";";
617  }
618  }
619  }
620 
621  if( opts.has(ViewOptions::WITH_QUERY_STR))
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 
634  if( opts.has(ViewOptions::WITH_FRAGMENT))
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  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"),
1272  )
1273  );
1274  }
1275 
1276 
1277  // ---------------------------------------------------------------
1278  void
1279  UrlBase::setPathParam(const std::string &param, const std::string &value)
1280  {
1282  pmap[param] = value;
1283  setPathParamsMap(pmap);
1284  }
1285 
1286 
1287  // ---------------------------------------------------------------
1288  void
1290  {
1293  pvec,
1294  config("psep_querystr")
1295  )
1296  );
1297  }
1298 
1299 
1300  // ---------------------------------------------------------------
1301  void
1303  {
1304  if( config("psep_querystr").empty() ||
1305  config("vsep_querystr").empty())
1306  {
1308  _("Query string parsing not supported for this URL")
1309  ));
1310  }
1313  pmap,
1314  config("psep_querystr"),
1315  config("vsep_querystr"),
1316  config("safe_querystr"),
1317  eflag
1318  )
1319  );
1320  }
1321 
1322  // ---------------------------------------------------------------
1323  void
1324  UrlBase::setQueryParam(const std::string &param, const std::string &value)
1325  {
1327  std::string newval = url::join(
1328  ParamMap{ {param,value} },
1329  config("psep_querystr"),
1330  config("vsep_querystr"),
1331  config("safe_querystr"),
1333  );
1334  zypp::url::ParamMap newmap;
1335  url::split(
1336  newmap,
1337  newval,
1338  config("psep_querystr"),
1339  config("vsep_querystr"),
1341  );
1342  pmap[newmap.begin()->first] = newmap.begin()->second;
1344  }
1345 
1346  // ---------------------------------------------------------------
1347  void
1348  UrlBase::delQueryParam(const std::string &param)
1349  {
1351  for ( auto it = pmap.begin(), last = pmap.end(); it != last; ) {
1352  if ( url::decode( it->first ) == param )
1353  it = pmap.erase( it );
1354  else
1355  ++it;
1356  }
1358  }
1359 
1360 
1361  // ---------------------------------------------------------------
1362  std::string
1363  UrlBase::cleanupPathName(const std::string &path) const
1364  {
1365  bool authority = !getHost(zypp::url::E_ENCODED).empty();
1366  return cleanupPathName(path, authority);
1367  }
1368 
1369  // ---------------------------------------------------------------
1370  std::string
1371  UrlBase::cleanupPathName(const std::string &path, bool authority) const
1372  {
1373  std::string copy( path);
1374 
1375  // decode the first slash if it is encoded ...
1376  if(copy.size() >= 3 && copy.at(0) != '/' &&
1377  str::toLower(copy.substr(0, 3)) == "%2f")
1378  {
1379  copy.replace(0, 3, "/");
1380  }
1381 
1382  // if path begins with a double slash ("//"); encode the second
1383  // slash [minimal and IMO sufficient] before the first path
1384  // segment, to fulfill the path-absolute rule of RFC 3986
1385  // disallowing a "//" if no authority is present.
1386  if( authority)
1387  {
1388  //
1389  // rewrite of "//" to "/%2f" not required, use config
1390  //
1391  if(config("path_encode_slash2") == "y")
1392  {
1393  // rewrite "//" ==> "/%2f"
1394  if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
1395  {
1396  copy.replace(1, 1, "%2F");
1397  }
1398  }
1399  else
1400  {
1401  // rewrite "/%2f" ==> "//"
1402  if(copy.size() >= 4 && copy.at(0) == '/' &&
1403  str::toLower(copy.substr(1, 4)) == "%2f")
1404  {
1405  copy.replace(1, 4, "/");
1406  }
1407  }
1408  }
1409  else
1410  {
1411  // rewrite of "//" to "/%2f" is required (no authority)
1412  if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
1413  {
1414  copy.replace(1, 1, "%2F");
1415  }
1416  }
1417  return copy;
1418  }
1419 
1420 
1421  // ---------------------------------------------------------------
1422  bool
1423  UrlBase::isValidHost(const std::string &host) const
1424  {
1425  try
1426  {
1428  if( str::regex_match(host, regx))
1429  {
1430  struct in6_addr ip;
1431  std::string temp( host.substr(1, host.size()-2));
1432 
1433  return inet_pton(AF_INET6, temp.c_str(), &ip) > 0;
1434  }
1435  else
1436  {
1437  // matches also IPv4 dotted-decimal adresses...
1438  std::string temp( zypp::url::decode(host));
1440  return str::regex_match(temp, regx);
1441  }
1442  }
1443  catch( ... )
1444  {}
1445 
1446  return false;
1447  }
1448 
1449 
1450  // ---------------------------------------------------------------
1451  bool
1452  UrlBase::isValidPort(const std::string &port) const
1453  {
1454  try
1455  {
1456  str::regex regx(RX_VALID_PORT);
1457  if( str::regex_match(port, regx))
1458  {
1459  long pnum = str::strtonum<long>(port);
1460  return ( pnum >= 1 && pnum <= USHRT_MAX);
1461  }
1462  }
1463  catch( ... )
1464  {}
1465  return false;
1466  }
1467 
1468 
1470  } // namespace url
1472 
1474 } // namespace zypp
1476 /*
1477 ** vim: set ts=2 sts=2 sw=2 ai et:
1478 */
std::string pathparams
Definition: UrlBase.cc:198
std::string toLower(const std::string &s)
Return lowercase version of s.
Definition: String.cc:178
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
virtual std::string getQueryString() const
Returns the encoded query string component of the URL.
Definition: UrlBase.cc:698
Internal data used by UrlBase.
Definition: UrlBase.cc:179
#define _(MSG)
Definition: Gettext.h:39
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:424
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:1013
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
ViewOptions vopts
Definition: UrlBase.cc:190
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 _fullQuerytsr
Definition: UrlBase.cc:172
Definition: Arch.h:363
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:37
std::vector< std::string > ParamVec
A parameter vector container.
Definition: UrlUtils.h:40
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:1081
virtual void setPathParams(const std::string &params)
Set the path parameters.
Definition: UrlBase.cc:1226
UrlBaseData * m_data
Definition: UrlBase.h:1082
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:1243
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:986
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:1047
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 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
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:164
virtual std::string getFragment(EEncoding eflag) const
Returns the encoded fragment component of the URL.
Definition: UrlBase.cc:711
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:252
virtual void setQueryString(const std::string &querystr)
Set the query string in the URL.
Definition: UrlBase.cc:969
std::string toUpper(const std::string &s)
Return uppercase version of s.
Definition: String.cc:201
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
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:1371
std::string decode(const std::string &str, bool allowNUL)
Decodes a URL percent encoded string.
Definition: UrlUtils.cc:87
#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:1166
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 pathname
Definition: UrlBase.cc:197
virtual bool isValidPort(const std::string &port) const
Verifies specified port number.
Definition: UrlBase.cc:1452
#define a_zA_Z
Definition: UrlBase.cc:31
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:1256
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
std::string user
Definition: UrlBase.cc:193
virtual bool isValidHost(const std::string &host) const
Verifies specified host or IP.
Definition: UrlBase.cc:1423
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
virtual void setQueryStringMap(const zypp::url::ParamMap &qmap, EEncoding eflag)
Set the query parameters.
Definition: UrlBase.cc:1302
virtual void setPathParam(const std::string &param, const std::string &value)
Set or add value for the specified path parameter.
Definition: UrlBase.cc:1279
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:1289
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
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:1348
Flag to request decoded string(s).
Definition: UrlUtils.h:54