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