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