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