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