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