libzypp  11.13.5
UrlBase.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include "zypp/url/UrlBase.h"
13 #include "zypp/base/String.h"
14 #include "zypp/base/Gettext.h"
15 #include "zypp/base/Regex.h"
16 
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  setScheme(scheme);
235  setAuthority(authority);
236  setPathData(pathdata);
237  setQueryString(querystr);
239  }
240 
241 
242  // ---------------------------------------------------------------
243  void
245  {
246  config("sep_pathparams", ";");
247  config("psep_pathparam", ",");
248  config("vsep_pathparam", "=");
249 
250  config("psep_querystr", "&");
251  config("vsep_querystr", "=");
252 
253  config("safe_username", "~!$&'()*+=,;");
254  config("safe_password", "~!$&'()*+=,:;");
255  config("safe_hostname", "[:]");
256  config("safe_pathname", "~!$&'()*+=,:@/");
257  config("safe_pathparams", "~!$&'()*+=,:;@/");
258  config("safe_querystr", "~!$&'()*+=,:;@/?");
259  config("safe_fragment", "~!$&'()*+=,:;@/?");
260 
261  // y=yes (allowed)
262  // n=no (disallowed, exception if !empty)
263  config("with_authority", "y");
264  config("with_port", "y");
265 
266  // y=yes (required but don't throw if empty)
267  // n=no (not required, ignore if empty)
268  // m=mandatory (exception if empty)
269  config("require_host", "n");
270  config("require_pathname","n");
271 
272  // y=yes (encode 2. slash even if authority present)
273  // n=no (don't encode 2. slash if authority present)
274  config("path_encode_slash2", "n");
275 
276  config("rx_username", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,;~\\._-]|%[a-fA-F0-9]{2})+$");
277  config("rx_password", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,:;~\\._-]|%[a-fA-F0-9]{2})+$");
278 
279  config("rx_pathname", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,:@/~\\._-]|%[a-fA-F0-9]{2})+$");
280  config("rx_pathparams", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,:;@/~\\._-]|%[a-fA-F0-9]{2})+$");
281 
282  config("rx_querystr", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
283  config("rx_fragment", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
284  }
285 
286 
287  // ---------------------------------------------------------------
288  void
289  UrlBase::config(const std::string &opt, const std::string &val)
290  {
291  m_data->config[opt] = val;
292  }
293 
294 
295  // ---------------------------------------------------------------
296  std::string
297  UrlBase::config(const std::string &opt) const
298  {
299  UrlConfig::const_iterator v( m_data->config.find(opt));
300  if( v != m_data->config.end())
301  return v->second;
302  else
303  return std::string();
304  }
305 
306 
307  // ---------------------------------------------------------------
310  {
311  return m_data->vopts;
312  }
313 
314 
315  // ---------------------------------------------------------------
316  void
318  {
319  m_data->vopts = vopts;
320  }
321 
322 
323  // ---------------------------------------------------------------
324  void
326  {
329  *m_data = UrlBaseData();
330  m_data->config = config;
331  m_data->vopts = vopts;
332  }
333 
334 
335  // ---------------------------------------------------------------
336  UrlBase *
338  {
339  return new UrlBase(*this);
340  }
341 
342 
343  // ---------------------------------------------------------------
346  {
347  return UrlSchemes();
348  }
349 
350 
351  // ---------------------------------------------------------------
352  bool
353  UrlBase::isKnownScheme(const std::string &scheme) const
354  {
355  std::string lscheme( str::toLower(scheme));
356  UrlSchemes schemes( getKnownSchemes());
357  UrlSchemes::const_iterator s;
358 
359  for(s=schemes.begin(); s!=schemes.end(); ++s)
360  {
361  if( lscheme == str::toLower(*s))
362  return true;
363  }
364  return false;
365  }
366 
367 
368  // ---------------------------------------------------------------
369  bool
370  UrlBase::isValidScheme(const std::string &scheme) const
371  {
372  bool valid = false;
373  try
374  {
376  valid = str::regex_match(scheme, rex);
377  }
378  catch( ... )
379  {}
380 
381  if(valid)
382  {
383  std::string lscheme( str::toLower(scheme));
384  UrlSchemes schemes( getKnownSchemes());
385 
386  if( schemes.empty())
387  return true;
388 
389  UrlSchemes::const_iterator s;
390  for(s=schemes.begin(); s!=schemes.end(); ++s)
391  {
392  if( lscheme == str::toLower(*s))
393  return true;
394  }
395  }
396  return false;
397  }
398 
399 
400  // ---------------------------------------------------------------
401  bool
403  {
404  /*
405  ** scheme is the only mandatory component
406  ** for all url's and is already verified,
407  ** (except for empty Url instances), so
408  ** Url with empty scheme is never valid.
409  */
410  if( getScheme().empty())
411  return false;
412 
413  std::string host( getHost(zypp::url::E_ENCODED));
414  if( host.empty() && config("require_host") != "n")
415  return false;
416 
417  std::string path( getPathName(zypp::url::E_ENCODED));
418  if( path.empty() && config("require_pathname") != "n")
419  return false;
420 
421  /*
422  ** path has to begin with "/" if authority avaliable
423  ** if host is set after the pathname, we can't throw
424  */
425  if( !host.empty() && !path.empty() && path.at(0) != '/')
426  return false;
427 
428  return true;
429  }
430 
431 
432  // ---------------------------------------------------------------
433  std::string
435  {
436  return asString(getViewOptions());
437  }
438 
439 
440  // ---------------------------------------------------------------
441  std::string
443  {
444  std::string url;
445  UrlBaseData tmp;
446 
447  if( opts.has(ViewOptions::WITH_SCHEME))
448  {
449  tmp.scheme = getScheme();
450  if( !tmp.scheme.empty())
451  {
452  url += tmp.scheme + ":";
453 
454  if( opts.has(ViewOptions::WITH_HOST))
455  {
457  if( !tmp.host.empty())
458  {
459  url += "//";
460 
462  {
464  if( !tmp.user.empty())
465  {
466  url += tmp.user;
467 
469  {
471  if( !tmp.pass.empty())
472  {
473  url += ":" + tmp.pass;
474  }
475  }
476  url += "@";
477  }
478  }
479 
480  url += tmp.host;
481 
482  if( opts.has(ViewOptions::WITH_PORT))
483  {
484  tmp.port = getPort();
485  if( !tmp.port.empty())
486  {
487  url += ":" + tmp.port;
488  }
489  }
490  }
491  else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
492  {
493  url += "//";
494  }
495  }
496  else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
497  {
498  url += "//";
499  }
500  }
501  }
502 
504  {
506  if( !tmp.pathname.empty())
507  {
508  if(url.find("/") != std::string::npos)
509  {
510  // Url contains authority (that may be empty),
511  // we may need a rewrite of the encoded path.
512  tmp.pathname = cleanupPathName(tmp.pathname, true);
513  if(tmp.pathname.at(0) != '/')
514  {
515  url += "/";
516  }
517  }
518  url += tmp.pathname;
519 
521  {
522  tmp.pathparams = getPathParams();
523  if( !tmp.pathparams.empty())
524  {
525  url += ";" + tmp.pathparams;
526  }
527  else if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
528  {
529  url += ";";
530  }
531  }
532  }
533  else if( opts.has(ViewOptions::EMPTY_PATH_NAME)
534  && url.find("/") != std::string::npos)
535  {
536  url += "/";
538  {
539  url += ";";
540  }
541  }
542  }
543 
545  {
546  tmp.querystr = getQueryString();
547  if( !tmp.querystr.empty())
548  {
549  url += "?" + tmp.querystr;
550  }
551  else if( opts.has(ViewOptions::EMPTY_QUERY_STR))
552  {
553  url += "?";
554  }
555  }
556 
558  {
560  if( !tmp.fragment.empty())
561  {
562  url += "#" + tmp.fragment;
563  }
564  else if( opts.has(ViewOptions::EMPTY_FRAGMENT))
565  {
566  url += "#";
567  }
568  }
569 
570  return url;
571  }
572 
573 
574  // ---------------------------------------------------------------
575  std::string
577  {
578  return m_data->scheme;
579  }
580 
581 
582  // ---------------------------------------------------------------
583  std::string
585  {
586  std::string str;
587  if( !getHost(zypp::url::E_ENCODED).empty())
588  {
589  if( !getUsername(zypp::url::E_ENCODED).empty())
590  {
592  if( !getPassword(zypp::url::E_ENCODED).empty())
593  {
594  str += ":" + getPassword(zypp::url::E_ENCODED);
595  }
596  str += "@";
597  }
598 
600  if( !getPort().empty())
601  {
602  str += ":" + getPort();
603  }
604  }
605  return str;
606  }
607 
608 
609  // ---------------------------------------------------------------
610  std::string
612  {
614  config("sep_pathparams") +
615  getPathParams();
616  }
617 
618 
619  // ---------------------------------------------------------------
620  std::string
622  {
623  return m_data->querystr;
624  }
625 
626 
627  // ---------------------------------------------------------------
628  std::string
630  {
631  if(eflag == zypp::url::E_DECODED)
633  else
634  return m_data->fragment;
635  }
636 
637 
638  // ---------------------------------------------------------------
639  std::string
641  {
642  if(eflag == zypp::url::E_DECODED)
643  return zypp::url::decode(m_data->user);
644  else
645  return m_data->user;
646  }
647 
648 
649  // ---------------------------------------------------------------
650  std::string
652  {
653  if(eflag == zypp::url::E_DECODED)
654  return zypp::url::decode(m_data->pass);
655  else
656  return m_data->pass;
657  }
658 
659 
660  // ---------------------------------------------------------------
661  std::string
663  {
664  if(eflag == zypp::url::E_DECODED)
665  return zypp::url::decode(m_data->host);
666  else
667  return m_data->host;
668  }
669 
670 
671  // ---------------------------------------------------------------
672  std::string
674  {
675  return m_data->port;
676  }
677 
678 
679  // ---------------------------------------------------------------
680  std::string
682  {
683  if(eflag == zypp::url::E_DECODED)
685  else
687  }
688 
689 
690  // ---------------------------------------------------------------
691  std::string
693  {
694  return m_data->pathparams;
695  }
696 
697 
698  // ---------------------------------------------------------------
701  {
702  zypp::url::ParamVec pvec;
703  if( config("psep_pathparam").empty())
704  {
705  pvec.push_back(getPathParams());
706  }
707  else
708  {
710  pvec,
711  getPathParams(),
712  config("psep_pathparam")
713  );
714  }
715  return pvec;
716  }
717 
718 
719  // ---------------------------------------------------------------
722  {
723  if( config("psep_pathparam").empty() ||
724  config("vsep_pathparam").empty())
725  {
727  "Path parameter parsing not supported for this URL"
728  ));
729  }
730  zypp::url::ParamMap pmap;
732  pmap,
733  getPathParams(),
734  config("psep_pathparam"),
735  config("vsep_pathparam"),
736  eflag
737  );
738  return pmap;
739  }
740 
741 
742  // ---------------------------------------------------------------
743  std::string
744  UrlBase::getPathParam(const std::string &param, EEncoding eflag) const
745  {
746  zypp::url::ParamMap pmap( getPathParamsMap( eflag));
747  zypp::url::ParamMap::const_iterator i( pmap.find(param));
748 
749  return i != pmap.end() ? i->second : std::string();
750  }
751 
752 
753  // ---------------------------------------------------------------
756  {
757  zypp::url::ParamVec pvec;
758  if( config("psep_querystr").empty())
759  {
760  pvec.push_back(getQueryString());
761  }
762  else
763  {
765  pvec,
766  getQueryString(),
767  config("psep_querystr")
768  );
769  }
770  return pvec;
771  }
772 
773 
774  // ---------------------------------------------------------------
777  {
778  if( config("psep_querystr").empty() ||
779  config("vsep_querystr").empty())
780  {
782  _("Query string parsing not supported for this URL")
783  ));
784  }
785  zypp::url::ParamMap pmap;
787  pmap,
788  getQueryString(),
789  config("psep_querystr"),
790  config("vsep_querystr"),
791  eflag
792  );
793  return pmap;
794  }
795 
796 
797  // ---------------------------------------------------------------
798  std::string
799  UrlBase::getQueryParam(const std::string &param, EEncoding eflag) const
800  {
801  zypp::url::ParamMap pmap( getQueryStringMap( eflag));
802  zypp::url::ParamMap::const_iterator i( pmap.find(param));
803 
804  return i != pmap.end() ? i->second : std::string();
805  }
806 
807 
808  // ---------------------------------------------------------------
809  void
810  UrlBase::setScheme(const std::string &scheme)
811  {
812  if( isValidScheme(scheme))
813  {
814  m_data->scheme = str::toLower(scheme);
815  }
816  else
817  if( scheme.empty())
818  {
820  _("Url scheme is a required component")
821  ));
822  }
823  else
824  {
826  str::form(_("Invalid Url scheme '%s'"), scheme.c_str())
827  ));
828  }
829  }
830 
831 
832  // ---------------------------------------------------------------
833  void
834  UrlBase::setAuthority(const std::string &authority)
835  {
836  std::string s = authority;
838 
839  std::string username, password, host, port;
840 
841  if ((p=s.find('@')) != std::string::npos)
842  {
843  q = s.find(':');
844  if (q != std::string::npos && q < p)
845  {
846  setUsername(s.substr(0, q), zypp::url::E_ENCODED);
847  setPassword(s.substr(q+1, p-q-1), zypp::url::E_ENCODED);
848  }
849  else
850  setUsername(s.substr(0, p), zypp::url::E_ENCODED);
851  s = s.substr(p+1);
852  }
853  if ((p = s.rfind(':')) != std::string::npos && ( (q = s.rfind(']')) == std::string::npos || q < p) )
854  {
855  setHost(s.substr(0, p));
856  setPort(s.substr(p+1));
857  }
858  else
859  setHost(s);
860  }
861 
862  // ---------------------------------------------------------------
863  void
864  UrlBase::setPathData(const std::string &pathdata)
865  {
866  size_t pos = std::string::npos;
867  std::string sep(config("sep_pathparams"));
868 
869  if( !sep.empty())
870  pos = pathdata.find(sep);
871 
872  if( pos != std::string::npos)
873  {
874  setPathName(pathdata.substr(0, pos),
876  setPathParams(pathdata.substr(pos + 1));
877  }
878  else
879  {
880  setPathName(pathdata,
882  setPathParams("");
883  }
884  }
885 
886 
887  // ---------------------------------------------------------------
888  void
889  UrlBase::setQueryString(const std::string &querystr)
890  {
891  if( querystr.empty())
892  {
893  m_data->querystr = querystr;
894  }
895  else
896  {
897  checkUrlData(querystr, "query string", config("rx_querystr"));
898 
899  m_data->querystr = querystr;
900  }
901  }
902 
903 
904  // ---------------------------------------------------------------
905  void
906  UrlBase::setFragment(const std::string &fragment,
907  EEncoding eflag)
908  {
909  if( fragment.empty())
910  {
911  m_data->fragment = fragment;
912  }
913  else
914  {
915  if(eflag == zypp::url::E_ENCODED)
916  {
917  checkUrlData(fragment, "fragment", config("rx_fragment"));
918 
919  m_data->fragment = fragment;
920  }
921  else
922  {
924  fragment, config("safe_fragment")
925  );
926  }
927  }
928  }
929 
930 
931  // ---------------------------------------------------------------
932  void
933  UrlBase::setUsername(const std::string &user,
934  EEncoding eflag)
935  {
936  if( user.empty())
937  {
938  m_data->user = user;
939  }
940  else
941  {
942  if( config("with_authority") != "y")
943  {
945  _("Url scheme does not allow a username")
946  ));
947  }
948 
949  if(eflag == zypp::url::E_ENCODED)
950  {
951  checkUrlData(user, "username", config("rx_username"));
952 
953  m_data->user = user;
954  }
955  else
956  {
958  user, config("safe_username")
959  );
960  }
961  }
962  }
963 
964 
965  // ---------------------------------------------------------------
966  void
967  UrlBase::setPassword(const std::string &pass,
968  EEncoding eflag)
969  {
970  if( pass.empty())
971  {
972  m_data->pass = pass;
973  }
974  else
975  {
976  if( config("with_authority") != "y")
977  {
979  _("Url scheme does not allow a password")
980  ));
981  }
982 
983  if(eflag == zypp::url::E_ENCODED)
984  {
985  checkUrlData(pass, "password", config("rx_password"), false);
986 
987  m_data->pass = pass;
988  }
989  else
990  {
992  pass, config("safe_password")
993  );
994  }
995  }
996  }
997 
998 
999  // ---------------------------------------------------------------
1000  void
1001  UrlBase::setHost(const std::string &host)
1002  {
1003  if( host.empty())
1004  {
1005  if(config("require_host") == "m")
1006  {
1008  _("Url scheme requires a host component")
1009  ));
1010  }
1011  m_data->host = host;
1012  }
1013  else
1014  {
1015  if( config("with_authority") != "y")
1016  {
1018  _("Url scheme does not allow a host component")
1019  ));
1020  }
1021 
1022  if( isValidHost(host))
1023  {
1024  std::string temp;
1025 
1026  // always decode in case isValidHost()
1027  // is reimplemented and supports also
1028  // the [v ... ] notation.
1029  if( host.at(0) == '[')
1030  {
1031  temp = str::toUpper(zypp::url::decode(host));
1032  }
1033  else
1034  {
1035  temp = str::toLower(zypp::url::decode(host));
1036  }
1037 
1039  temp, config("safe_hostname")
1040  );
1041  }
1042  else
1043  {
1045  str::form(_("Invalid host component '%s'"), host.c_str())
1046  ));
1047  }
1048  }
1049  }
1050 
1051 
1052  // ---------------------------------------------------------------
1053  void
1054  UrlBase::setPort(const std::string &port)
1055  {
1056  if( port.empty())
1057  {
1058  m_data->port = port;
1059  }
1060  else
1061  {
1062  if( config("with_authority") != "y" ||
1063  config("with_port") != "y")
1064  {
1066  _("Url scheme does not allow a port")
1067  ));
1068  }
1069 
1070  if( isValidPort(port))
1071  {
1072  m_data->port = port;
1073  }
1074  else
1075  {
1077  str::form(_("Invalid port component '%s'"), port.c_str())
1078  ));
1079  }
1080  }
1081  }
1082 
1083 
1084  // ---------------------------------------------------------------
1085  void
1086  UrlBase::setPathName(const std::string &path,
1087  EEncoding eflag)
1088  {
1089  if( path.empty())
1090  {
1091  if(config("require_pathname") == "m")
1092  {
1094  _("Url scheme requires path name")
1095  ));
1096  }
1097  m_data->pathname = path;
1098  }
1099  else
1100  {
1101  if(eflag == zypp::url::E_ENCODED)
1102  {
1103  checkUrlData(path, "path name", config("rx_pathname"));
1104 
1105  if( !getHost(zypp::url::E_ENCODED).empty())
1106  {
1107  // has to begin with a "/". For consistency with
1108  // setPathName while the host is empty, we allow
1109  // it in encoded ("%2f") form - cleanupPathName()
1110  // will fix / decode the first slash if needed.
1111  if(!(path.at(0) == '/' || (path.size() >= 3 &&
1112  str::toLower(path.substr(0, 3)) == "%2f")))
1113  {
1115  _("Relative path not allowed if authority exists")
1116  ));
1117  }
1118  }
1119 
1120  m_data->pathname = cleanupPathName(path);
1121  }
1122  else // zypp::url::E_DECODED
1123  {
1124  if( !getHost(zypp::url::E_ENCODED).empty())
1125  {
1126  if(path.at(0) != '/')
1127  {
1129  _("Relative path not allowed if authority exists")
1130  ));
1131  }
1132  }
1133 
1136  path, config("safe_pathname")
1137  )
1138  );
1139  }
1140  }
1141  }
1142 
1143 
1144  // ---------------------------------------------------------------
1145  void
1146  UrlBase::setPathParams(const std::string &params)
1147  {
1148  if( params.empty())
1149  {
1150  m_data->pathparams = params;
1151  }
1152  else
1153  {
1154  checkUrlData(params, "path parameters", config("rx_pathparams"));
1155 
1156  m_data->pathparams = params;
1157  }
1158  }
1159 
1160 
1161  // ---------------------------------------------------------------
1162  void
1164  {
1165  setPathParams(
1167  pvec,
1168  config("psep_pathparam")
1169  )
1170  );
1171  }
1172 
1173 
1174  // ---------------------------------------------------------------
1175  void
1177  {
1178  if( config("psep_pathparam").empty() ||
1179  config("vsep_pathparam").empty())
1180  {
1182  "Path Parameter parsing not supported for this URL"
1183  ));
1184  }
1185  setPathParams(
1187  pmap,
1188  config("psep_pathparam"),
1189  config("vsep_pathparam"),
1190  config("safe_pathparams")
1191  )
1192  );
1193  }
1194 
1195 
1196  // ---------------------------------------------------------------
1197  void
1198  UrlBase::setPathParam(const std::string &param, const std::string &value)
1199  {
1201  pmap[param] = value;
1202  setPathParamsMap(pmap);
1203  }
1204 
1205 
1206  // ---------------------------------------------------------------
1207  void
1209  {
1212  pvec,
1213  config("psep_querystr")
1214  )
1215  );
1216  }
1217 
1218 
1219  // ---------------------------------------------------------------
1220  void
1222  {
1223  if( config("psep_querystr").empty() ||
1224  config("vsep_querystr").empty())
1225  {
1227  _("Query string parsing not supported for this URL")
1228  ));
1229  }
1232  pmap,
1233  config("psep_querystr"),
1234  config("vsep_querystr"),
1235  config("safe_querystr")
1236  )
1237  );
1238  }
1239 
1240  // ---------------------------------------------------------------
1241  void
1242  UrlBase::setQueryParam(const std::string &param, const std::string &value)
1243  {
1245  pmap[param] = value;
1246  setQueryStringMap(pmap);
1247  }
1248 
1249  // ---------------------------------------------------------------
1250  void
1251  UrlBase::delQueryParam(const std::string &param)
1252  {
1254  pmap.erase(param);
1255  setQueryStringMap(pmap);
1256  }
1257 
1258 
1259  // ---------------------------------------------------------------
1260  std::string
1261  UrlBase::cleanupPathName(const std::string &path) const
1262  {
1263  bool authority = !getHost(zypp::url::E_ENCODED).empty();
1264  return cleanupPathName(path, authority);
1265  }
1266 
1267  // ---------------------------------------------------------------
1268  std::string
1269  UrlBase::cleanupPathName(const std::string &path, bool authority) const
1270  {
1271  std::string copy( path);
1272 
1273  // decode the first slash if it is encoded ...
1274  if(copy.size() >= 3 && copy.at(0) != '/' &&
1275  str::toLower(copy.substr(0, 3)) == "%2f")
1276  {
1277  copy.replace(0, 3, "/");
1278  }
1279 
1280  // if path begins with a double slash ("//"); encode the second
1281  // slash [minimal and IMO sufficient] before the first path
1282  // segment, to fulfill the path-absolute rule of RFC 3986
1283  // disallowing a "//" if no authority is present.
1284  if( authority)
1285  {
1286  //
1287  // rewrite of "//" to "/%2f" not required, use config
1288  //
1289  if(config("path_encode_slash2") == "y")
1290  {
1291  // rewrite "//" ==> "/%2f"
1292  if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
1293  {
1294  copy.replace(1, 1, "%2F");
1295  }
1296  }
1297  else
1298  {
1299  // rewrite "/%2f" ==> "//"
1300  if(copy.size() >= 4 && copy.at(0) == '/' &&
1301  str::toLower(copy.substr(1, 4)) == "%2f")
1302  {
1303  copy.replace(1, 4, "/");
1304  }
1305  }
1306  }
1307  else
1308  {
1309  // rewrite of "//" to "/%2f" is required (no authority)
1310  if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
1311  {
1312  copy.replace(1, 1, "%2F");
1313  }
1314  }
1315  return copy;
1316  }
1317 
1318 
1319  // ---------------------------------------------------------------
1320  bool
1321  UrlBase::isValidHost(const std::string &host) const
1322  {
1323  try
1324  {
1326  if( str::regex_match(host, regx))
1327  {
1328  struct in6_addr ip;
1329  std::string temp( host.substr(1, host.size()-2));
1330 
1331  return inet_pton(AF_INET6, temp.c_str(), &ip) > 0;
1332  }
1333  else
1334  {
1335  // matches also IPv4 dotted-decimal adresses...
1336  std::string temp( zypp::url::decode(host));
1338  return str::regex_match(temp, regx);
1339  }
1340  }
1341  catch( ... )
1342  {}
1343 
1344  return false;
1345  }
1346 
1347 
1348  // ---------------------------------------------------------------
1349  bool
1350  UrlBase::isValidPort(const std::string &port) const
1351  {
1352  try
1353  {
1354  str::regex regx(RX_VALID_PORT);
1355  if( str::regex_match(port, regx))
1356  {
1357  long pnum = str::strtonum<long>(port);
1358  return ( pnum >= 1 && pnum <= USHRT_MAX);
1359  }
1360  }
1361  catch( ... )
1362  {}
1363  return false;
1364  }
1365 
1366 
1368  } // namespace url
1370 
1372 } // namespace zypp
1374 /*
1375 ** vim: set ts=2 sts=2 sw=2 ai et:
1376 */