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