- Converted to use zypp::Exception derived exceptions
[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 asString() 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                    bool               show=true)
135       {
136         if( regx.empty() || regx == "^$")
137         {
138           ZYPP_THROW(UrlNotAllowedException(
139             std::string("Url scheme does not allow a " + name)
140           ));
141         }
142         else
143         {
144           bool valid = false;
145           try
146           {
147             str::regex rex(regx);
148             valid = str::regex_match(data, rex);
149           }
150           catch( ... )
151           {}
152
153           if( !valid)
154           {
155             if( show)
156             {
157               ZYPP_THROW(UrlBadComponentException(
158                 std::string("Invalid " + name + " component '" +
159                             data + "'")
160               ));
161             }
162             else
163             {
164               ZYPP_THROW(UrlBadComponentException(
165                 std::string("Invalid " + name + " component")
166               ));
167             }
168           }
169         }
170       }
171
172     } // namespace
173
174
175     // ---------------------------------------------------------------
176     UrlBase::~UrlBase()
177     {
178       delete m_data;
179       m_data = NULL;
180     }
181
182
183     // ---------------------------------------------------------------
184     UrlBase::UrlBase()
185       : m_data( new UrlBaseData())
186     {
187       configure();
188     }
189
190
191     // ---------------------------------------------------------------
192     UrlBase::UrlBase(const UrlBase &url)
193       : m_data( new UrlBaseData( *(url.m_data)))
194     {
195     }
196
197
198     // ---------------------------------------------------------------
199     UrlBase::UrlBase(const std::string &scheme,
200                      const std::string &authority,
201                      const std::string &pathdata,
202                      const std::string &querystr,
203                      const std::string &fragment)
204       : m_data( new UrlBaseData())
205     {
206       configure();
207       init(scheme, authority, pathdata, querystr, fragment);
208     }
209
210
211     // ---------------------------------------------------------------
212     void
213     UrlBase::init(const std::string &scheme,
214                   const std::string &authority,
215                   const std::string &pathdata,
216                   const std::string &querystr,
217                   const std::string &fragment)
218     {
219       setScheme(scheme);
220       setAuthority(authority);
221       setPathData(pathdata);
222       setQueryString(querystr);
223       setFragment(fragment, zypp::url::E_ENCODED);
224     }
225
226
227     // ---------------------------------------------------------------
228     void
229     UrlBase::configure()
230     {
231       config("sep_pathparams",  ";");
232       config("psep_pathparam",  ",");
233       config("vsep_pathparam",  "=");
234
235       config("psep_querystr",   "&");
236       config("vsep_querystr",   "=");
237
238       config("safe_username",   "~!$&'()*+=,;");
239       config("safe_password",   "~!$&'()*+=,:;");
240       config("safe_hostname",   "[:]");
241       config("safe_pathname",   "~!$&'()*+=,:@/");
242       config("safe_pathparams", "~!$&'()*+=,:;@/");
243       config("safe_querystr",   "~!$&'()*+=,:;@/?");
244       config("safe_fragment",   "~!$&'()*+=,:;@/?");
245
246       config("with_authority",  "y");
247       config("require_scheme",  "y");
248
249       config("rx_username",     "^([a-zA-Z0-9!$&'\\(\\)*+=,;~\\._-]|%[a-fA-F0-9]{2})+$");
250       config("rx_password",     "^([a-zA-Z0-9!$&'\\(\\)*+=,:;~\\._-]|%[a-fA-F0-9]{2})+$");
251
252       config("rx_pathname",     "^([a-zA-Z0-9!$&'\\(\\)*+=,:@/~\\._-]|%[a-fA-F0-9]{2})+$");
253       config("rx_pathparams",   "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/~\\._-]|%[a-fA-F0-9]{2})+$");
254
255       config("rx_querystr",     "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
256       config("rx_fragment",     "^([a-zA-Z0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
257     }
258
259
260     // ---------------------------------------------------------------
261     void
262     UrlBase::config(const std::string &opt, const std::string &val)
263     {
264       m_data->config[opt] = val;
265     }
266
267
268     // ---------------------------------------------------------------
269     std::string
270     UrlBase::config(const std::string &opt) const
271     {
272       UrlConfig::const_iterator v( m_data->config.find(opt));
273       if( v != m_data->config.end())
274         return v->second;
275       else
276         return std::string();
277     }
278
279
280     // ---------------------------------------------------------------
281     ViewOptions
282     UrlBase::getViewOptions() const
283     {
284       return m_data->vopts;
285     }
286
287
288     // ---------------------------------------------------------------
289     void
290     UrlBase::setViewOptions(const ViewOptions &vopts)
291     {
292         m_data->vopts = vopts;
293     }
294
295
296     // ---------------------------------------------------------------
297     void
298     UrlBase::clear()
299     {
300       zypp::url::UrlConfig   config(m_data->config);
301       zypp::url::ViewOptions vopts(m_data->vopts);
302       *m_data = UrlBaseData();
303       m_data->config = config;
304       m_data->vopts  = vopts;
305     }
306
307
308     // ---------------------------------------------------------------
309     UrlBase *
310     UrlBase::clone() const
311     {
312       return new UrlBase(*this);
313     }
314
315
316     // ---------------------------------------------------------------
317     zypp::url::UrlSchemes
318     UrlBase::getKnownSchemes() const
319     {
320       return UrlSchemes();
321     }
322
323
324     // ---------------------------------------------------------------
325     bool
326     UrlBase::isKnownScheme(const std::string &scheme) const
327     {
328       std::string                lscheme( str::toLower(scheme));
329       UrlSchemes                 schemes( getKnownSchemes());
330       UrlSchemes::const_iterator s;
331
332       for(s=schemes.begin(); s!=schemes.end(); ++s)
333       {
334         if( lscheme == str::toLower(*s))
335           return true;
336       }
337       return false;
338     }
339
340
341     // ---------------------------------------------------------------
342     bool
343     UrlBase::isValidScheme(const std::string &scheme) const
344     {
345       bool valid = false;
346       try
347       {
348         str::regex rex(RX_VALID_SCHEME);
349         valid = str::regex_match(scheme, rex);
350       }
351       catch( ... )
352       {}
353
354       if((scheme.empty() && config("require_scheme") != "y") || valid)
355       {
356         std::string    lscheme( str::toLower(scheme));
357         UrlSchemes     schemes( getKnownSchemes());
358
359         if( schemes.empty())
360           return true;
361
362         UrlSchemes::const_iterator s;
363         for(s=schemes.begin(); s!=schemes.end(); ++s)
364         {
365           if( lscheme == str::toLower(*s))
366             return true;
367         }
368       }
369       return false;
370     }
371
372
373     // ---------------------------------------------------------------
374     bool
375     UrlBase::isValid() const
376     {
377       return !getScheme().empty();
378     }
379
380
381     // ---------------------------------------------------------------
382     std::string
383     UrlBase::asString() const
384     {
385       return asString(getViewOptions());
386     }
387
388
389     // ---------------------------------------------------------------
390     std::string
391     UrlBase::asString(const zypp::url::ViewOptions &opts) const
392     {
393       std::string   url;
394       UrlBaseData   tmp;
395
396       if( opts.has(ViewOptions::WITH_SCHEME))
397       {
398         tmp.scheme = getScheme();
399         if( !tmp.scheme.empty())
400         {
401           url += tmp.scheme + ":";
402
403           if( opts.has(ViewOptions::WITH_HOST))
404           {
405             tmp.host = getHost(zypp::url::E_ENCODED);
406             if( !tmp.host.empty())
407             {
408               url += "//";
409
410               if( opts.has(ViewOptions::WITH_USERNAME))
411               {
412                 tmp.user = getUsername(zypp::url::E_ENCODED);
413                 if( !tmp.user.empty())
414                 {
415                   url += tmp.user;
416
417                   if( opts.has(ViewOptions::WITH_PASSWORD))
418                   {
419                     tmp.pass = getPassword(zypp::url::E_ENCODED);
420                     if( !tmp.pass.empty())
421                     {
422                       url += ":" + tmp.pass;
423                     }
424                   }
425                   url += "@";
426                 }
427               }
428
429               url += tmp.host;
430
431               if( opts.has(ViewOptions::WITH_PORT))
432               {
433                 tmp.port = getPort();
434                 if( !tmp.port.empty())
435                 {
436                   url += ":" + tmp.port;
437                 }
438               }
439             }
440           }
441           else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
442           {
443             url += "//";
444           }
445         }
446       }
447
448       if( opts.has(ViewOptions::WITH_PATH_NAME))
449       {
450         tmp.pathname = getPathName(zypp::url::E_ENCODED);
451         if( !tmp.pathname.empty())
452         {
453           if( (!tmp.host.empty() || opts.has(ViewOptions::EMPTY_AUTHORITY))
454               && (tmp.pathname.at(0) != '/'))
455           {
456             url += "/";
457           }
458           url += tmp.pathname;
459
460           if( opts.has(ViewOptions::WITH_PATH_PARAMS))
461           {
462             tmp.pathparams = getPathParams();
463             if( !tmp.pathparams.empty())
464             {
465               url += ";" + tmp.pathparams;
466             }
467             else if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
468             {
469               url += ";";
470             }
471           }
472         }
473         else if( opts.has(ViewOptions::EMPTY_PATH_NAME))
474         {
475           url += "/";
476           if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
477           {
478             url += ";";
479           }
480         }
481       }
482
483       if( opts.has(ViewOptions::WITH_QUERY_STR))
484       {
485         tmp.querystr = getQueryString();
486         if( !tmp.querystr.empty())
487         {
488           url += "?" + tmp.querystr;
489         }
490         else if( opts.has(ViewOptions::EMPTY_QUERY_STR))
491         {
492           url += "?";
493         }
494       }
495
496       if( opts.has(ViewOptions::WITH_FRAGMENT))
497       {
498         tmp.fragment = getFragment(zypp::url::E_ENCODED);
499         if( !tmp.fragment.empty())
500         {
501           url += "#" + tmp.fragment;
502         }
503         else if( opts.has(ViewOptions::EMPTY_FRAGMENT))
504         {
505           url += "#";
506         }
507       }
508
509       return url;
510     }
511
512
513     // ---------------------------------------------------------------
514     std::string
515     UrlBase::getScheme() const
516     {
517       return m_data->scheme;
518     }
519
520
521     // ---------------------------------------------------------------
522     std::string
523     UrlBase::getAuthority() const
524     {
525       std::string str;
526       if( !getHost(zypp::url::E_ENCODED).empty())
527       {
528         if( !getUsername(zypp::url::E_ENCODED).empty())
529         {
530           str = getUsername(zypp::url::E_ENCODED);
531           if( !getPassword(zypp::url::E_ENCODED).empty())
532           {
533             str += ":" + getPassword(zypp::url::E_ENCODED);
534           }
535           str += "@";
536         }
537
538         str += getHost(zypp::url::E_ENCODED);
539         if( !getPort().empty())
540         {
541           str += ":" + getPort();
542         }
543       }
544       return str;
545     }
546
547
548     // ---------------------------------------------------------------
549     std::string
550     UrlBase::getPathData() const
551     {
552       return getPathName(zypp::url::E_ENCODED) +
553              config("sep_pathparams") +
554              getPathParams();
555     }
556
557
558     // ---------------------------------------------------------------
559     std::string
560     UrlBase::getQueryString() const
561     {
562       return m_data->querystr;
563     }
564
565
566     // ---------------------------------------------------------------
567     std::string
568     UrlBase::getFragment(EEncoding eflag) const
569     {
570       if(eflag == zypp::url::E_DECODED)
571         return zypp::url::decode(m_data->fragment);
572       else
573         return m_data->fragment;
574     }
575
576
577     // ---------------------------------------------------------------
578     std::string
579     UrlBase::getUsername(EEncoding eflag) const
580     {
581       if(eflag == zypp::url::E_DECODED)
582         return zypp::url::decode(m_data->user);
583       else
584         return m_data->user;
585     }
586
587
588     // ---------------------------------------------------------------
589     std::string
590     UrlBase::getPassword(EEncoding eflag) const
591     {
592       if(eflag == zypp::url::E_DECODED)
593         return zypp::url::decode(m_data->pass);
594       else
595         return m_data->pass;
596     }
597
598
599     // ---------------------------------------------------------------
600     std::string
601     UrlBase::getHost(EEncoding eflag) const
602     {
603       if(eflag == zypp::url::E_DECODED)
604         return zypp::url::decode(m_data->host);
605       else
606         return m_data->host;
607     }
608
609
610     // ---------------------------------------------------------------
611     std::string
612     UrlBase::getPort() const
613     {
614       return m_data->port;
615     }
616
617
618     // ---------------------------------------------------------------
619     std::string
620     UrlBase::getPathName(EEncoding eflag) const
621     {
622       if(eflag == zypp::url::E_DECODED)
623         return zypp::url::decode(m_data->pathname);
624       else
625         return m_data->pathname;
626     }
627
628
629     // ---------------------------------------------------------------
630     std::string
631     UrlBase::getPathParams() const
632     {
633       return m_data->pathparams;
634     }
635
636
637     // ---------------------------------------------------------------
638     zypp::url::ParamVec
639     UrlBase::getPathParamsVec() const
640     {
641       zypp::url::ParamVec pvec;
642       if( config("psep_pathparam").empty())
643       {
644         pvec.push_back(getPathParams());
645       }
646       else
647       {
648         zypp::url::split(
649           pvec,
650           getPathParams(),
651           config("psep_pathparam")
652         );
653       }
654       return pvec;
655     }
656
657
658     // ---------------------------------------------------------------
659     zypp::url::ParamMap
660     UrlBase::getPathParamsMap(EEncoding eflag) const
661     {
662       if( config("psep_pathparam").empty() ||
663           config("vsep_pathparam").empty())
664       {
665         ZYPP_THROW(UrlNotSupportedException(
666           "Path parameter parsing not supported for this URL"
667         ));
668       }
669       zypp::url::ParamMap pmap;
670       zypp::url::split(
671         pmap,
672         getPathParams(),
673         config("psep_pathparam"),
674         config("vsep_pathparam"),
675         eflag
676       );
677       return pmap;
678     }
679
680
681     // ---------------------------------------------------------------
682     std::string
683     UrlBase::getPathParam(const std::string &param, EEncoding eflag) const
684     {
685       zypp::url::ParamMap pmap( getPathParamsMap( eflag));
686       zypp::url::ParamMap::const_iterator i( pmap.find(param));
687
688       return i != pmap.end() ? i->second : std::string();
689     }
690
691
692     // ---------------------------------------------------------------
693     zypp::url::ParamVec
694     UrlBase::getQueryStringVec() const
695     {
696       zypp::url::ParamVec pvec;
697       if( config("psep_querystr").empty())
698       {
699         pvec.push_back(getQueryString());
700       }
701       else
702       {
703         zypp::url::split(
704           pvec,
705           getQueryString(),
706           config("psep_querystr")
707         );
708       }
709       return pvec;
710     }
711
712
713     // ---------------------------------------------------------------
714     zypp::url::ParamMap
715     UrlBase::getQueryStringMap(EEncoding eflag) const
716     {
717       if( config("psep_querystr").empty() ||
718           config("vsep_querystr").empty())
719       {
720         ZYPP_THROW(UrlNotSupportedException(
721           "Query string parsing not supported for this URL"
722         ));
723       }
724       zypp::url::ParamMap pmap;
725       zypp::url::split(
726         pmap,
727         getQueryString(),
728         config("psep_querystr"),
729         config("vsep_querystr"),
730         eflag
731       );
732       return pmap;
733     }
734
735
736     // ---------------------------------------------------------------
737     std::string
738     UrlBase::getQueryParam(const std::string &param, EEncoding eflag) const
739     {
740       zypp::url::ParamMap pmap( getQueryStringMap( eflag));
741       zypp::url::ParamMap::const_iterator i( pmap.find(param));
742
743       return i != pmap.end() ? i->second : std::string();
744     }
745
746
747     // ---------------------------------------------------------------
748     void
749     UrlBase::setScheme(const std::string &scheme)
750     {
751       if( isValidScheme(scheme))
752       {
753         m_data->scheme = str::toLower(scheme);
754       }
755       else
756       if( scheme.empty())
757       {
758         ZYPP_THROW(UrlBadComponentException(
759           std::string("Url scheme is a required component")
760         ));
761       }
762       else
763       {
764         ZYPP_THROW(UrlBadComponentException(
765           std::string("Invalid Url scheme '" + scheme + "'")
766         ));
767       }
768     }
769
770
771     // ---------------------------------------------------------------
772     void
773     UrlBase::setAuthority(const std::string &authority)
774     {
775       str::smatch out;
776       bool        ret = false;
777
778       try
779       {
780         str::regex  rex(RX_SPLIT_AUTHORITY);
781         ret = str::regex_match(authority, out, rex);
782       }
783       catch( ... )
784       {}
785
786       if( ret && out.size() == 8)
787       {
788         setUsername(out[2].str(), zypp::url::E_ENCODED);
789         setPassword(out[4].str(), zypp::url::E_ENCODED);
790         setHost(out[5].str());
791         setPort(out[7].str());
792       }
793       else
794       {
795         ZYPP_THROW(UrlParsingException(
796           "Unable to parse Url authority"
797         ));
798       }
799     }
800
801     // ---------------------------------------------------------------
802     void
803     UrlBase::setPathData(const std::string &pathdata)
804     {
805       size_t      pos = std::string::npos;
806       std::string sep(config("sep_pathparams"));
807
808       if( !sep.empty())
809         pos = pathdata.find(sep);
810
811       if( pos != std::string::npos)
812       {
813         setPathName(pathdata.substr(0, pos),
814                     zypp::url::E_ENCODED);
815         setPathParams(pathdata.substr(pos + 1));
816       }
817       else
818       {
819         setPathName(pathdata,
820                     zypp::url::E_ENCODED);
821         setPathParams("");
822       }
823     }
824
825
826     // ---------------------------------------------------------------
827     void
828     UrlBase::setQueryString(const std::string &querystr)
829     {
830       if( querystr.empty())
831       {
832         m_data->querystr = querystr;
833       }
834       else
835       {
836         checkUrlData(querystr, "query string", config("rx_querystr"));
837
838         m_data->querystr = querystr;
839       }
840     }
841
842
843     // ---------------------------------------------------------------
844     void
845     UrlBase::setFragment(const std::string &fragment,
846                          EEncoding         eflag)
847     {
848       if( fragment.empty())
849       {
850         m_data->fragment = fragment;
851       }
852       else
853       {
854         if(eflag == zypp::url::E_ENCODED)
855         {
856           checkUrlData(fragment, "fragment", config("rx_fragment"));
857
858           m_data->fragment = fragment;
859         }
860         else
861         {
862           m_data->fragment = zypp::url::encode(
863             fragment, config("safe_password")
864           );
865         }
866       }
867     }
868
869
870     // ---------------------------------------------------------------
871     void
872     UrlBase::setUsername(const std::string &user,
873                          EEncoding         eflag)
874     {
875       if( user.empty())
876       {
877         m_data->user = user;
878       }
879       else
880       {
881         if( config("with_authority") != "y")
882         {
883           ZYPP_THROW(UrlNotAllowedException(
884             std::string("Url scheme does not allow a username")
885           ));
886         }
887
888         if(eflag == zypp::url::E_ENCODED)
889         {
890           checkUrlData(user, "username", config("rx_username"));
891
892           m_data->user = user;
893         }
894         else
895         {
896           m_data->user = zypp::url::encode(
897             user, config("safe_username")
898           );
899         }
900       }
901     }
902
903
904     // ---------------------------------------------------------------
905     void
906     UrlBase::setPassword(const std::string &pass,
907                          EEncoding         eflag)
908     {
909       if( pass.empty())
910       {
911         m_data->pass = pass;
912       }
913       else
914       {
915         if( config("with_authority") != "y")
916         {
917           ZYPP_THROW(UrlNotAllowedException(
918             std::string("Url scheme does not allow a password")
919           ));
920         }
921
922         if(eflag == zypp::url::E_ENCODED)
923         {
924           checkUrlData(pass, "password", config("rx_password"), false);
925
926           m_data->pass = pass;
927         }
928         else
929         {
930           m_data->pass = zypp::url::encode(
931             pass, config("safe_password")
932           );
933         }
934       }
935     }
936
937
938     // ---------------------------------------------------------------
939     void
940     UrlBase::setHost(const std::string &host)
941     {
942       if( host.empty())
943       {
944         m_data->host = host;
945       }
946       else
947       {
948         if( config("with_authority") != "y")
949         {
950           ZYPP_THROW(UrlNotAllowedException(
951             std::string("Url scheme does not allow a host")
952           ));
953         }
954
955         if( isValidHost(host))
956         {
957           std::string temp;
958
959           // always decode in case isValidHost()
960           // is reimplemented and supports also
961           // the [v ... ] notation.
962           if( host.at(0) == '[')
963           {
964             temp = str::toUpper(zypp::url::decode(host));
965           }
966           else
967           {
968             temp = str::toLower(zypp::url::decode(host));
969           }
970
971           m_data->host = zypp::url::encode(
972             temp, config("safe_hostname")
973           );
974         }
975         else
976         {
977           ZYPP_THROW(UrlBadComponentException(
978             std::string("Invalid host argument '" + host + "'")
979           ));
980         }
981       }
982     }
983
984
985     // ---------------------------------------------------------------
986     void
987     UrlBase::setPort(const std::string &port)
988     {
989       if( port.empty())
990       {
991         m_data->port = port;
992       }
993       else
994       {
995         if( config("with_authority") != "y")
996         {
997           ZYPP_THROW(UrlNotAllowedException(
998             std::string("Url scheme does not allow a port")
999           ));
1000         }
1001
1002         if( isValidPort(port))
1003         {
1004           m_data->port = port;
1005         }
1006         else
1007         {
1008           ZYPP_THROW(UrlBadComponentException(
1009             std::string("Invalid host argument '" + port + "'")
1010           ));
1011         }
1012       }
1013     }
1014
1015
1016     // ---------------------------------------------------------------
1017     void
1018     UrlBase::setPathName(const std::string &path,
1019                          EEncoding         eflag)
1020     {
1021       if( path.empty())
1022       {
1023         m_data->pathname = path;
1024       }
1025       else
1026       {
1027         std::string data;
1028         if(eflag == zypp::url::E_ENCODED)
1029         {
1030           checkUrlData(path, "path name", config("rx_pathname"));
1031
1032           data = cleanupPathName(zypp::url::decode(path));
1033         }
1034         else
1035         {
1036           data = cleanupPathName(path);
1037         }
1038
1039         m_data->pathname = zypp::url::encode(
1040           data, config("safe_pathname")
1041         );
1042       }
1043     }
1044
1045
1046     // ---------------------------------------------------------------
1047     void
1048     UrlBase::setPathParams(const std::string &params)
1049     {
1050       if( params.empty())
1051       {
1052         m_data->pathparams = params;
1053       }
1054       else
1055       {
1056         checkUrlData(params, "path parameters", config("rx_pathparams"));
1057
1058         m_data->pathparams = params;
1059       }
1060     }
1061
1062
1063     // ---------------------------------------------------------------
1064     void
1065     UrlBase::setPathParamsVec(const zypp::url::ParamVec &pvec)
1066     {
1067       setPathParams(
1068         zypp::url::join(
1069           pvec,
1070           config("psep_pathparam")
1071         )
1072       );
1073     }
1074
1075
1076     // ---------------------------------------------------------------
1077     void
1078     UrlBase::setPathParamsMap(const zypp::url::ParamMap &pmap)
1079     {
1080       if( config("psep_pathparam").empty() ||
1081           config("vsep_pathparam").empty())
1082       {
1083         ZYPP_THROW(UrlNotSupportedException(
1084           "Path Parameter parsing not supported for this URL"
1085         ));
1086       }
1087       setPathParams(
1088         zypp::url::join(
1089           pmap,
1090           config("psep_pathparam"),
1091           config("vsep_pathparam"),
1092           config("safe_pathparams")
1093         )
1094       );
1095     }
1096
1097
1098     // ---------------------------------------------------------------
1099     void
1100     UrlBase::setPathParam(const std::string &param, const std::string &value)
1101     {
1102           zypp::url::ParamMap pmap( getPathParamsMap(zypp::url::E_DECODED));
1103           pmap[param] = value;
1104           setPathParamsMap(pmap);
1105     }
1106
1107
1108     // ---------------------------------------------------------------
1109     void
1110     UrlBase::setQueryStringVec(const zypp::url::ParamVec &pvec)
1111     {
1112       setQueryString(
1113         zypp::url::join(
1114           pvec,
1115           config("psep_querystr")
1116         )
1117       );
1118     }
1119
1120
1121     // ---------------------------------------------------------------
1122     void
1123     UrlBase::setQueryStringMap(const zypp::url::ParamMap &pmap)
1124     {
1125       if( config("psep_querystr").empty() ||
1126           config("vsep_querystr").empty())
1127       {
1128         ZYPP_THROW(UrlNotSupportedException(
1129           "Query string parsing not supported for this URL"
1130         ));
1131       }
1132       setQueryString(
1133         zypp::url::join(
1134           pmap,
1135           config("psep_querystr"),
1136           config("vsep_querystr"),
1137           config("safe_querystr")
1138         )
1139       );
1140     }
1141
1142     // ---------------------------------------------------------------
1143     void
1144     UrlBase::setQueryParam(const std::string &param, const std::string &value)
1145     {
1146           zypp::url::ParamMap pmap( getQueryStringMap(zypp::url::E_DECODED));
1147           pmap[param] = value;
1148           setQueryStringMap(pmap);
1149     }
1150
1151
1152     // ---------------------------------------------------------------
1153     std::string
1154     UrlBase::cleanupPathName(const std::string &path)
1155     {
1156       size_t pos = 0;
1157
1158       while( pos < path.length() && path.at(pos) == '/')
1159         pos++;
1160
1161       if( pos > 1)
1162       {
1163         // make sure, there is not more than
1164         // _one_ leading "/" in the path name.
1165         return path.substr(pos - 1);
1166       }
1167
1168       return std::string(path);
1169     }
1170
1171
1172     // ---------------------------------------------------------------
1173     bool
1174     UrlBase::isValidHost(const std::string &host)
1175     {
1176       try
1177       {
1178         str::regex regx(RX_VALID_HOSTIPV6);
1179         if( str::regex_match(host, regx))
1180         {
1181           struct in6_addr ip;
1182           std::string temp( host.substr(1, host.size()-2));
1183           
1184           return inet_pton(AF_INET6, temp.c_str(), &ip) > 0;
1185         }
1186         else
1187         {
1188           // matches also IPv4 dotted-decimal adresses...
1189           std::string temp( zypp::url::decode(host));
1190           str::regex  regx(RX_VALID_HOSTNAME);
1191           return str::regex_match(temp, regx);
1192         }
1193       }
1194       catch( ... )
1195       {}
1196
1197       return false;
1198     }
1199
1200
1201     // ---------------------------------------------------------------
1202     bool
1203     UrlBase::isValidPort(const std::string &port)
1204     {
1205       try
1206       {
1207         str::regex regx(RX_VALID_PORT);
1208         if( str::regex_match(port, regx))
1209         {
1210           long pnum = str::strtonum<long>(port);
1211           return ( pnum >= 1 && pnum <= USHRT_MAX);
1212         }
1213       }
1214       catch( ... )
1215       {}
1216
1217       return false;
1218     }
1219
1220
1221     //////////////////////////////////////////////////////////////////
1222   } // namespace url
1223   ////////////////////////////////////////////////////////////////////
1224
1225   ////////////////////////////////////////////////////////////////////
1226 } // namespace zypp
1227 //////////////////////////////////////////////////////////////////////
1228 /*
1229 ** vim: set ts=2 sts=2 sw=2 ai et:
1230 */