- Added flag if encoded or not to set functions
[platform/upstream/libzypp.git] / zypp / url / UrlBase.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /**
10  * \file zypp/url/UrlBase.cc
11  */
12 #include <zypp/url/UrlBase.h>
13 #include <zypp/base/String.h>
14
15 #include <stdexcept>
16 #include <climits>
17 #include <errno.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <arpa/inet.h>
21
22
23 // ---------------------------------------------------------------
24 /*
25 ** authority = //[user [:password] @ ] host [:port]
26 **
27 ** host      = hostname | IPv4 | "[" IPv6-IP "]" | "[v...]"
28 */
29 #define RX_SPLIT_AUTHORITY \
30         "^(([^:@]*)([:]([^@]*))?@)?(\\[[^]]+\\]|[^:]+)?([:](.*))?"
31
32 #define RX_VALID_SCHEME    "^[a-zA-Z][a-zA-Z0-9\\.+-]*$"
33
34 #define RX_VALID_PORT      "^[0-9]{1,5}$"
35
36 #define RX_VALID_HOSTNAME  "^[[:alnum:]]+([\\.-][[:alnum:]]+)*$"
37
38 #define RX_VALID_HOSTIPV4  \
39         "^([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})$"
40
41 #define RX_VALID_HOSTIPV6  \
42         "^\\[[:a-fA-F0-9]+(:[0-9]{1,3}(\\.[0-9]{1,3}){3})?\\]$"
43
44
45 //////////////////////////////////////////////////////////////////////
46 namespace zypp
47 { ////////////////////////////////////////////////////////////////////
48
49   ////////////////////////////////////////////////////////////////////
50   namespace url
51   { //////////////////////////////////////////////////////////////////
52
53
54     // ---------------------------------------------------------------
55     /*
56     ** URL toString() view option constants:
57     */
58     const ViewOptions ViewOptions::WITH_SCHEME       = 0x0001;
59     const ViewOptions ViewOptions::WITH_USERNAME     = 0x0002;
60     const ViewOptions ViewOptions::WITH_PASSWORD     = 0x0004;
61     const ViewOptions ViewOptions::WITH_HOST         = 0x0008;
62     const ViewOptions ViewOptions::WITH_PORT         = 0x0010;
63     const ViewOptions ViewOptions::WITH_PATH_NAME    = 0x0020;
64     const ViewOptions ViewOptions::WITH_PATH_PARAMS  = 0x0040;
65     const ViewOptions ViewOptions::WITH_QUERY_STR    = 0x0080;
66     const ViewOptions ViewOptions::WITH_FRAGMENT     = 0x0100;
67     const ViewOptions ViewOptions::EMPTY_AUTHORITY   = 0x0200;
68     const ViewOptions ViewOptions::EMPTY_PATH_NAME   = 0x0400;
69     const ViewOptions ViewOptions::EMPTY_PATH_PARAMS = 0x0800;
70     const ViewOptions ViewOptions::EMPTY_QUERY_STR   = 0x1000;
71     const ViewOptions ViewOptions::EMPTY_FRAGMENT    = 0x2000;
72     const ViewOptions ViewOptions::DEFAULTS          = 0x07bb;
73     /*
74                       ViewOptions::WITH_SCHEME       +
75                       ViewOptions::WITH_USERNAME     +
76                       ViewOptions::WITH_HOST         +
77                       ViewOptions::WITH_PORT         +
78                       ViewOptions::WITH_PATH_NAME    +
79                       ViewOptions::WITH_QUERY_STR    +
80                       ViewOptions::WITH_FRAGMENT     +
81                       ViewOptions::EMPTY_AUTHORITY   +
82                       ViewOptions::EMPTY_PATH_NAME;
83     */
84
85
86     // ---------------------------------------------------------------
87     /*
88     ** Behaviour configuration variables.
89     */
90     typedef std::map< std::string, std::string > UrlConfig;
91
92
93     // ---------------------------------------------------------------
94     /**
95      * \brief Internal data used by UrlBase.
96      */
97     class UrlBaseData
98     {
99     public:
100       UrlBaseData()
101       {}
102
103       UrlBaseData(const UrlConfig &conf)
104         : config(conf)
105       {}
106
107       UrlConfig       config;
108       ViewOptions     vopts;
109
110       std::string     scheme;
111       std::string     user;
112       std::string     pass;
113       std::string     host;
114       std::string     port;
115       std::string     pathname;
116       std::string     pathparams;
117       std::string     querystr;
118       std::string     fragment;
119     };
120
121
122     // ---------------------------------------------------------------
123     /*
124     ** Anonymous/internal utility namespace:
125     */
126     namespace // anonymous
127     {
128
129                         // -------------------------------------------------------------
130       inline void
131       checkUrlData(const std::string &data,
132                    const std::string &name,
133                    const std::string &regx)
134       {
135         if( regx.empty() || regx == "^$")
136         {
137           throw std::invalid_argument(
138             std::string("Url scheme does not allow a " +
139                         name)
140           );
141         }
142         else
143         if( !str::regex_match(data, str::regex(regx)))
144         {
145           throw std::invalid_argument(
146             std::string("Invalid " + name + " argument '" +
147                         data + "'")
148             );
149         }
150       }
151
152     } // namespace
153
154
155     // ---------------------------------------------------------------
156     UrlBase::~UrlBase()
157     {
158       delete m_data;
159       m_data = NULL;
160     }
161
162
163     // ---------------------------------------------------------------
164     UrlBase::UrlBase()
165       : m_data( new UrlBaseData())
166     {
167       configure();
168     }
169
170
171     // ---------------------------------------------------------------
172     UrlBase::UrlBase(const UrlBase &url)
173       : m_data( new UrlBaseData( *(url.m_data)))
174     {
175     }
176
177
178     // ---------------------------------------------------------------
179     UrlBase::UrlBase(const std::string &scheme,
180                      const std::string &authority,
181                      const std::string &pathdata,
182                      const std::string &querystr,
183                      const std::string &fragment)
184       : m_data( new UrlBaseData())
185     {
186       configure();
187       init(scheme, authority, pathdata, querystr, fragment);
188     }
189
190
191     // ---------------------------------------------------------------
192     void
193     UrlBase::init(const std::string &scheme,
194                   const std::string &authority,
195                   const std::string &pathdata,
196                   const std::string &querystr,
197                   const std::string &fragment)
198     {
199       setScheme(scheme);
200       setAuthority(authority);
201       setPathData(pathdata);
202       setQueryString(querystr);
203       setFragment(fragment, zypp::url::E_ENCODED);
204     }
205
206
207     // ---------------------------------------------------------------
208     void
209     UrlBase::configure()
210     {
211       config("sep_pathparams",  ";");
212       config("psep_pathparam",  ",");
213       config("vsep_pathparam",  "=");
214
215       config("psep_querystr",   "&");
216       config("vsep_querystr",   "=");
217
218       config("safe_username",   "~!$&'()*+=,;");
219       config("safe_password",   "~!$&'()*+=,:;");
220       config("safe_hostname",   "[:]");
221       config("safe_pathname",   "~!$&'()*+=,:@/");
222       config("safe_pathparams", "~!$&'()*+=,:;@/");
223       config("safe_querystr",   "~!$&'()*+=,:;@/?");
224       config("safe_fragment",   "~!$&'()*+=,:;@/?");
225
226       config("with_authority",  "y");
227
228       config("rx_username",     "^([a-zA-Z0-9!$&'\\(\\)*+=,;~\\._-]|%[a-fA-F0-9]{2})+$");
229       config("rx_password",     "^([a-zA-Z0-9!$&'\\(\\)*+=,:;~\\._-]|%[a-fA-F0-9]{2})+$");
230
231       config("rx_pathname",     "^([a-zA-Z0-9!$&'\\(\\)*+=,:@/~\\._-]|%[a-fA-F0-9]{2})+$");
232       config("rx_pathparams",   "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/~\\._-]|%[a-fA-F0-9]{2})+$");
233
234       config("rx_querystr",     "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
235       config("rx_fragment",     "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
236     }
237
238
239     // ---------------------------------------------------------------
240     void
241     UrlBase::config(const std::string &opt, const std::string &val)
242     {
243       m_data->config[opt] = val;
244     }
245
246
247     // ---------------------------------------------------------------
248     std::string
249     UrlBase::config(const std::string &opt) const
250     {
251       UrlConfig::const_iterator v( m_data->config.find(opt));
252       if( v != m_data->config.end())
253         return v->second;
254       else
255         return std::string();
256     }
257
258
259     // ---------------------------------------------------------------
260     ViewOptions
261     UrlBase::getViewOptions() const
262     {
263       return m_data->vopts;
264     }
265
266
267     // ---------------------------------------------------------------
268     void
269     UrlBase::setViewOptions(const ViewOptions &vopts)
270     {
271         m_data->vopts = vopts;
272     }
273
274
275     // ---------------------------------------------------------------
276     void
277     UrlBase::clear()
278     {
279       zypp::url::UrlConfig   config(m_data->config);
280       zypp::url::ViewOptions vopts(m_data->vopts);
281       *m_data = UrlBaseData();
282       m_data->config = config;
283       m_data->vopts  = vopts;
284     }
285
286
287     // ---------------------------------------------------------------
288     UrlBase *
289     UrlBase::clone() const
290     {
291       return new UrlBase(*this);
292     }
293
294
295     // ---------------------------------------------------------------
296     zypp::url::UrlSchemes
297     UrlBase::getKnownSchemes() const
298     {
299       return UrlSchemes();
300     }
301
302
303     // ---------------------------------------------------------------
304     bool
305     UrlBase::isKnownScheme(const std::string &scheme) const
306     {
307       std::string                lscheme( str::toLower(scheme));
308       UrlSchemes                 schemes( getKnownSchemes());
309       UrlSchemes::const_iterator s;
310
311       for(s=schemes.begin(); s!=schemes.end(); ++s)
312       {
313         if( lscheme == str::toLower(*s))
314           return true;
315       }
316       return false;
317     }
318
319
320     // ---------------------------------------------------------------
321     bool
322     UrlBase::isValidScheme(const std::string &scheme) const
323     {
324       if(scheme.empty() ||
325          str::regex_match(scheme, str::regex(RX_VALID_SCHEME)))
326       {
327         std::string    lscheme( str::toLower(scheme));
328         UrlSchemes     schemes( getKnownSchemes());
329
330         if( schemes.empty())
331           return true;
332
333         UrlSchemes::const_iterator s;
334         for(s=schemes.begin(); s!=schemes.end(); ++s)
335         {
336           if( lscheme == str::toLower(*s))
337             return true;
338         }
339       }
340       return false;
341     }
342
343
344     // ---------------------------------------------------------------
345     bool
346     UrlBase::isValid() const
347     {
348       return !getScheme().empty();
349     }
350
351
352     // ---------------------------------------------------------------
353     std::string
354     UrlBase::toString() const
355     {
356       return toString(getViewOptions());
357     }
358
359
360     // ---------------------------------------------------------------
361     std::string
362     UrlBase::toString(const zypp::url::ViewOptions &opts) const
363     {
364       std::string   url;
365       UrlBaseData   tmp;
366
367       if( opts.has(ViewOptions::WITH_SCHEME))
368       {
369         tmp.scheme = getScheme();
370         if( !tmp.scheme.empty())
371         {
372           url += tmp.scheme + ":";
373
374           if( opts.has(ViewOptions::WITH_HOST))
375           {
376             tmp.host = getHost(zypp::url::E_ENCODED);
377             if( !tmp.host.empty())
378             {
379               url += "//";
380
381               if( opts.has(ViewOptions::WITH_USERNAME))
382               {
383                 tmp.user = getUsername(zypp::url::E_ENCODED);
384                 if( !tmp.user.empty())
385                 {
386                   url += tmp.user;
387
388                   if( opts.has(ViewOptions::WITH_PASSWORD))
389                   {
390                     tmp.pass = getPassword(zypp::url::E_ENCODED);
391                     if( !tmp.pass.empty())
392                     {
393                       url += ":" + tmp.pass;
394                     }
395                   }
396                   url += "@";
397                 }
398               }
399
400               url += tmp.host;
401
402               if( opts.has(ViewOptions::WITH_PORT))
403               {
404                 tmp.port = getPort();
405                 if( !tmp.port.empty())
406                 {
407                   url += ":" + tmp.port;
408                 }
409               }
410             }
411           }
412           else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
413           {
414             url += "//";
415           }
416         }
417       }
418
419       if( opts.has(ViewOptions::WITH_PATH_NAME))
420       {
421         tmp.pathname = getPathName(zypp::url::E_ENCODED);
422         if( !tmp.pathname.empty())
423         {
424           if( (!tmp.host.empty() || opts.has(ViewOptions::EMPTY_AUTHORITY))
425               && (tmp.pathname.at(0) != '/'))
426           {
427             url += "/";
428           }
429           url += tmp.pathname;
430
431           if( opts.has(ViewOptions::WITH_PATH_PARAMS))
432           {
433             tmp.pathparams = getPathParams();
434             if( !tmp.pathparams.empty())
435             {
436               url += ";" + tmp.pathparams;
437             }
438             else if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
439             {
440               url += ";";
441             }
442           }
443         }
444         else if( opts.has(ViewOptions::EMPTY_PATH_NAME))
445         {
446           url += "/";
447           if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
448           {
449             url += ";";
450           }
451         }
452       }
453
454       if( opts.has(ViewOptions::WITH_QUERY_STR))
455       {
456         tmp.querystr = getQueryString();
457         if( !tmp.querystr.empty())
458         {
459           url += "?" + tmp.querystr;
460         }
461         else if( opts.has(ViewOptions::EMPTY_QUERY_STR))
462         {
463           url += "?";
464         }
465       }
466
467       if( opts.has(ViewOptions::WITH_FRAGMENT))
468       {
469         tmp.fragment = getFragment(zypp::url::E_ENCODED);
470         if( !tmp.fragment.empty())
471         {
472           url += "#" + tmp.fragment;
473         }
474         else if( opts.has(ViewOptions::EMPTY_FRAGMENT))
475         {
476           url += "#";
477         }
478       }
479
480       return url;
481     }
482
483
484     // ---------------------------------------------------------------
485     std::string
486     UrlBase::getScheme() const
487     {
488       return m_data->scheme;
489     }
490
491
492     // ---------------------------------------------------------------
493     std::string
494     UrlBase::getAuthority() const
495     {
496       std::string str;
497       if( !getHost(zypp::url::E_ENCODED).empty())
498       {
499         if( !getUsername(zypp::url::E_ENCODED).empty())
500         {
501           str = getUsername(zypp::url::E_ENCODED);
502           if( !getPassword(zypp::url::E_ENCODED).empty())
503           {
504             str += ":" + getPassword(zypp::url::E_ENCODED);
505           }
506           str += "@";
507         }
508
509         str += getHost(zypp::url::E_ENCODED);
510         if( !getPort().empty())
511         {
512           str += ":" + getPort();
513         }
514       }
515       return str;
516     }
517
518
519     // ---------------------------------------------------------------
520     std::string
521     UrlBase::getPathData() const
522     {
523       return getPathName(zypp::url::E_ENCODED) +
524              config("sep_pathparams") +
525              getPathParams();
526     }
527
528
529     // ---------------------------------------------------------------
530     std::string
531     UrlBase::getQueryString() const
532     {
533       return m_data->querystr;
534     }
535
536
537     // ---------------------------------------------------------------
538     std::string
539     UrlBase::getFragment(EEncoding eflag) const
540     {
541       if(eflag == zypp::url::E_DECODED)
542         return zypp::url::decode(m_data->fragment);
543       else
544         return m_data->fragment;
545     }
546
547
548     // ---------------------------------------------------------------
549     std::string
550     UrlBase::getUsername(EEncoding eflag) const
551     {
552       if(eflag == zypp::url::E_DECODED)
553         return zypp::url::decode(m_data->user);
554       else
555         return m_data->user;
556     }
557
558
559     // ---------------------------------------------------------------
560     std::string
561     UrlBase::getPassword(EEncoding eflag) const
562     {
563       if(eflag == zypp::url::E_DECODED)
564         return zypp::url::decode(m_data->pass);
565       else
566         return m_data->pass;
567     }
568
569
570     // ---------------------------------------------------------------
571     std::string
572     UrlBase::getHost(EEncoding eflag) const
573     {
574       if(eflag == zypp::url::E_DECODED)
575         return zypp::url::decode(m_data->host);
576       else
577         return m_data->host;
578     }
579
580
581     // ---------------------------------------------------------------
582     std::string
583     UrlBase::getPort() const
584     {
585       return m_data->port;
586     }
587
588
589     // ---------------------------------------------------------------
590     std::string
591     UrlBase::getPathName(EEncoding eflag) const
592     {
593       if(eflag == zypp::url::E_DECODED)
594         return zypp::url::decode(m_data->pathname);
595       else
596         return m_data->pathname;
597     }
598
599
600     // ---------------------------------------------------------------
601     std::string
602     UrlBase::getPathParams() const
603     {
604       return m_data->pathparams;
605     }
606
607
608     // ---------------------------------------------------------------
609     zypp::url::ParamVec
610     UrlBase::getPathParamsVec() const
611     {
612       zypp::url::ParamVec pvec;
613       zypp::url::split(
614         pvec,
615         getPathParams(),
616         config("psep_pathparam")
617       );
618       return pvec;
619     }
620
621
622     // ---------------------------------------------------------------
623     zypp::url::ParamMap
624     UrlBase::getPathParamsMap(EEncoding eflag) const
625     {
626       zypp::url::ParamMap pmap;
627       zypp::url::split(
628         pmap,
629         getPathParams(),
630         config("psep_pathparam"),
631         config("vsep_pathparam"),
632         eflag
633       );
634       return pmap;
635     }
636
637
638     // ---------------------------------------------------------------
639     std::string
640     UrlBase::getPathParam(const std::string &param, EEncoding eflag) const
641     {
642       zypp::url::ParamMap pmap( getPathParamsMap( eflag));
643       zypp::url::ParamMap::const_iterator i( pmap.find(param));
644
645       return i != pmap.end() ? i->second : std::string();
646     }
647
648
649     // ---------------------------------------------------------------
650     zypp::url::ParamVec
651     UrlBase::getQueryStringVec() const
652     {
653       zypp::url::ParamVec pvec;
654       zypp::url::split(
655         pvec,
656         getQueryString(),
657         config("psep_querystr")
658       );
659       return pvec;
660     }
661
662
663     // ---------------------------------------------------------------
664     zypp::url::ParamMap
665     UrlBase::getQueryStringMap(EEncoding eflag) const
666     {
667       zypp::url::ParamMap pmap;
668       zypp::url::split(
669         pmap,
670         getQueryString(),
671         config("psep_querystr"),
672         config("vsep_querystr"),
673         eflag
674       );
675       return pmap;
676     }
677
678
679     // ---------------------------------------------------------------
680     std::string
681     UrlBase::getQueryParam(const std::string &param, EEncoding eflag) const
682     {
683       zypp::url::ParamMap pmap( getQueryStringMap( eflag));
684       zypp::url::ParamMap::const_iterator i( pmap.find(param));
685
686       return i != pmap.end() ? i->second : std::string();
687     }
688
689
690     // ---------------------------------------------------------------
691     void
692     UrlBase::setScheme(const std::string &scheme)
693     {
694       if( isValidScheme(scheme))
695       {
696         m_data->scheme = str::toLower(scheme);
697       }
698       else
699       {
700         throw std::invalid_argument(
701           std::string("Invalid Url scheme '" + scheme + "'")
702         );
703       }
704     }
705
706
707     // ---------------------------------------------------------------
708     void
709     UrlBase::setAuthority(const std::string &authority)
710     {
711       str::regex  rex(RX_SPLIT_AUTHORITY);
712       str::smatch out;
713       bool        ret = str::regex_match(authority, out, rex);
714
715       if( ret && out.size() == 8)
716       {
717         setUsername(out[2].str(), zypp::url::E_ENCODED);
718         setPassword(out[4].str(), zypp::url::E_ENCODED);
719         setHost(out[5].str());
720         setPort(out[7].str());
721       }
722       else
723       {
724         throw std::invalid_argument(
725           "Unable to parse Url authority"
726         );
727       }
728     }
729
730     // ---------------------------------------------------------------
731     void
732     UrlBase::setPathData(const std::string &pathdata)
733     {
734       size_t      pos = std::string::npos;
735       std::string sep(config("sep_pathparams"));
736
737       if( !sep.empty())
738         pos = pathdata.find(sep);
739
740       if( pos != std::string::npos)
741       {
742         setPathName(pathdata.substr(0, pos),
743                     zypp::url::E_ENCODED);
744         setPathParams(pathdata.substr(pos + 1));
745       }
746       else
747       {
748         setPathName(pathdata,
749                     zypp::url::E_ENCODED);
750         setPathParams("");
751       }
752     }
753
754
755     // ---------------------------------------------------------------
756     void
757     UrlBase::setQueryString(const std::string &querystr)
758     {
759       if( querystr.empty())
760       {
761         m_data->querystr = querystr;
762       }
763       else
764       {
765         checkUrlData(querystr, "query string", config("rx_querystr"));
766
767         m_data->querystr = querystr;
768       }
769     }
770
771
772     // ---------------------------------------------------------------
773     void
774     UrlBase::setFragment(const std::string &fragment,
775                          EEncoding         eflag)
776     {
777       if( fragment.empty())
778       {
779         m_data->fragment = fragment;
780       }
781       else
782       {
783         if(eflag == zypp::url::E_ENCODED)
784         {
785           checkUrlData(fragment, "fragment", config("rx_fragment"));
786
787           m_data->fragment = fragment;
788         }
789         else
790         {
791           m_data->fragment = zypp::url::encode(
792             fragment, config("safe_password")
793           );
794         }
795       }
796     }
797
798
799     // ---------------------------------------------------------------
800     void
801     UrlBase::setUsername(const std::string &user,
802                          EEncoding         eflag)
803     {
804       if( user.empty())
805       {
806         m_data->user = user;
807       }
808       else
809       {
810         if( config("with_authority") != "y")
811         {
812           throw std::invalid_argument(
813             std::string("Url scheme does not allow a username")
814           );
815         }
816
817         if(eflag == zypp::url::E_ENCODED)
818         {
819           checkUrlData(user, "username", config("rx_username"));
820
821           m_data->user = user;
822         }
823         else
824         {
825           m_data->user = zypp::url::encode(
826             user, config("safe_username")
827           );
828         }
829       }
830     }
831
832
833     // ---------------------------------------------------------------
834     void
835     UrlBase::setPassword(const std::string &pass,
836                          EEncoding         eflag)
837     {
838       if( pass.empty())
839       {
840         m_data->pass = pass;
841       }
842       else
843       {
844         if( config("with_authority") != "y")
845         {
846           throw std::invalid_argument(
847             std::string("Url scheme does not allow a password")
848           );
849         }
850
851         if(eflag == zypp::url::E_ENCODED)
852         {
853           checkUrlData(pass, "password", config("rx_password"));
854
855           m_data->pass = pass;
856         }
857         else
858         {
859           m_data->pass = zypp::url::encode(
860             pass, config("safe_password")
861           );
862         }
863       }
864     }
865
866
867     // ---------------------------------------------------------------
868     void
869     UrlBase::setHost(const std::string &host)
870     {
871       if( host.empty())
872       {
873         m_data->host = host;
874       }
875       else
876       {
877         if( config("with_authority") != "y")
878         {
879           throw std::invalid_argument(
880             std::string("Url scheme does not allow a host")
881           );
882         }
883
884         if( isValidHost(host))
885         {
886           std::string temp;
887           if( host.at(0) == '[')
888           {
889             temp = str::toUpper(zypp::url::decode(host));
890           }
891           else
892           {
893             temp = str::toLower(zypp::url::decode(host));
894           }
895
896           m_data->host = zypp::url::encode(
897             temp, config("safe_hostname")
898           );
899         }
900         else
901         {
902           throw std::invalid_argument(
903             std::string("Invalid host argument '" + host + "'")
904           );
905         }
906       }
907     }
908
909
910     // ---------------------------------------------------------------
911     void
912     UrlBase::setPort(const std::string &port)
913     {
914       if( port.empty())
915       {
916         m_data->port = port;
917       }
918       else
919       {
920         if( config("with_authority") != "y")
921         {
922           throw std::invalid_argument(
923             std::string("Url scheme does not allow a port")
924           );
925         }
926
927         if( isValidPort(port))
928         {
929           m_data->port = port;
930         }
931         else
932         {
933           throw std::invalid_argument(
934             std::string("Invalid host argument '" + port + "'")
935           );
936         }
937       }
938     }
939
940
941     // ---------------------------------------------------------------
942     void
943     UrlBase::setPathName(const std::string &path,
944                          EEncoding         eflag)
945     {
946       if( path.empty())
947       {
948         m_data->pathname = path;
949       }
950       else
951       {
952         std::string data;
953         if(eflag == zypp::url::E_ENCODED)
954         {
955           data = cleanupPathName(zypp::url::decode(path));
956         }
957         else
958         {
959           data = cleanupPathName(path);
960         }
961
962         m_data->pathname = zypp::url::encode(
963           data, config("safe_pathname")
964         );
965       }
966     }
967
968
969     // ---------------------------------------------------------------
970     void
971     UrlBase::setPathParams(const std::string &params)
972     {
973       if( params.empty())
974       {
975         m_data->pathparams = params;
976       }
977       else
978       {
979         checkUrlData(params, "path parameters", config("rx_pathparams"));
980
981         m_data->pathparams = params;
982       }
983     }
984
985
986     // ---------------------------------------------------------------
987     void
988     UrlBase::setPathParamsVec(const zypp::url::ParamVec &pvec)
989     {
990       setPathParams(
991         zypp::url::join(
992           pvec,
993           config("psep_pathparam")
994         )
995       );
996     }
997
998
999     // ---------------------------------------------------------------
1000     void
1001     UrlBase::setPathParamsMap(const zypp::url::ParamMap &pmap)
1002     {
1003       setPathParams(
1004         zypp::url::join(
1005           pmap,
1006           config("psep_pathparam"),
1007           config("vsep_pathparam"),
1008           config("safe_pathparams")
1009         )
1010       );
1011     }
1012
1013
1014     // ---------------------------------------------------------------
1015     void
1016     UrlBase::setPathParam(const std::string &param, const std::string &value)
1017     {
1018           zypp::url::ParamMap pmap( getPathParamsMap(zypp::url::E_DECODED));
1019           pmap[param] = value;
1020           setPathParamsMap(pmap);
1021     }
1022
1023
1024     // ---------------------------------------------------------------
1025     void
1026     UrlBase::setQueryStringVec(const zypp::url::ParamVec &pvec)
1027     {
1028       setQueryString(
1029         zypp::url::join(
1030           pvec,
1031           config("psep_querystr")
1032         )
1033       );
1034     }
1035
1036
1037     // ---------------------------------------------------------------
1038     void
1039     UrlBase::setQueryStringMap(const zypp::url::ParamMap &pmap)
1040     {
1041       setQueryString(
1042         zypp::url::join(
1043           pmap,
1044           config("psep_querystr"),
1045           config("vsep_querystr"),
1046           config("safe_querystr")
1047         )
1048       );
1049     }
1050
1051     // ---------------------------------------------------------------
1052     void
1053     UrlBase::setQueryParam(const std::string &param, const std::string &value)
1054     {
1055           zypp::url::ParamMap pmap( getQueryStringMap(zypp::url::E_DECODED));
1056           pmap[param] = value;
1057           setQueryStringMap(pmap);
1058     }
1059
1060
1061     // ---------------------------------------------------------------
1062     std::string
1063     UrlBase::cleanupPathName(const std::string &path)
1064     {
1065       size_t pos = 0;
1066
1067       while( pos < path.length() && path.at(pos) == '/')
1068         pos++;
1069
1070       if( pos > 1)
1071       {
1072         // make sure, there is not more than
1073         // _one_ leading "/" in the path name.
1074         return path.substr(pos - 1);
1075       }
1076
1077       return std::string(path);
1078     }
1079
1080
1081     // ---------------------------------------------------------------
1082     bool
1083     UrlBase::isValidHost(const std::string &host)
1084     {
1085       if( str::regex_match(host, str::regex(RX_VALID_HOSTIPV6)))
1086       {
1087         struct in6_addr ip;
1088
1089         if( inet_pton(AF_INET6, host.substr(1, host.size()-2).c_str(), &ip) > 0)
1090           return true;
1091         else
1092           return false;
1093       }
1094       else
1095       {
1096         // matches also IPv4 dotted-decimal adresses...
1097         std::string tmp( zypp::url::decode(host));
1098         return str::regex_match(tmp, str::regex(RX_VALID_HOSTNAME));
1099       }
1100     }
1101
1102
1103     // ---------------------------------------------------------------
1104     bool
1105     UrlBase::isValidPort(const std::string &port)
1106     {
1107         if( str::regex_match(port, str::regex(RX_VALID_PORT)))
1108         {
1109           long pnum = str::strtonum<long>(port);
1110           if( pnum >= 1 && pnum <= USHRT_MAX)
1111           {
1112             return true;
1113           }
1114         }
1115         return false;
1116     }
1117
1118
1119     //////////////////////////////////////////////////////////////////
1120   } // namespace url
1121   ////////////////////////////////////////////////////////////////////
1122
1123   ////////////////////////////////////////////////////////////////////
1124 } // namespace zypp
1125 //////////////////////////////////////////////////////////////////////
1126 /*
1127 ** vim: set ts=2 sts=2 sw=2 ai et:
1128 */