ignore
[platform/upstream/libzypp.git] / zypp / Url.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /**
10  * \file zypp/Url.cc
11  */
12 #include <zypp/Url.h>
13 #include <zypp/base/String.h>
14 #include <stdexcept>
15
16
17 //////////////////////////////////////////////////////////////////////
18 namespace zypp
19 { ////////////////////////////////////////////////////////////////////
20
21
22   using namespace zypp::url;
23
24
25   // -----------------------------------------------------------------
26   /*
27    * url       = [scheme:] [//authority] /path [?query] [#fragment]
28    */
29   #define RX_SPLIT_URL                       "^(([^:/?#]+):)?" \
30                                              "(//([^/?#]*))?"  \
31                                              "([^?#]*)"        \
32                                              "([?]([^#]*))?"   \
33                                              "(#(.*))?"
34
35
36   ////////////////////////////////////////////////////////////////////
37   namespace
38   { //////////////////////////////////////////////////////////////////
39
40
41     // ---------------------------------------------------------------
42     class LDAPUrl: public UrlBase
43     {
44     public:
45       LDAPUrl(): UrlBase()
46       {
47         configure();
48       }
49
50       LDAPUrl(const LDAPUrl &url): UrlBase(url)
51       {}
52
53       virtual UrlBase *
54       clone() const
55       {
56         return new LDAPUrl(*this);
57       }
58
59       virtual UrlSchemes
60       getKnownSchemes() const
61       {
62         UrlSchemes schemes(2);
63         schemes[0] = "ldap";
64         schemes[1] = "ldaps";
65         return schemes;
66       }
67
68       virtual void
69       configure()
70       {
71         config("sep_pathparams",  "");
72
73         config("psep_querystr",   "?");
74         config("vsep_querystr",   "");
75
76         // host is required (isValid=>false)
77         // but not mandatory (see RFC 2255),
78         // that is, accept empty host.
79         config("require_host",    "y");
80
81         // not allowed here
82         config("rx_username",     "");
83         config("rx_password",     "");
84         config("rx_fragment",     "");
85         config("rx_pathparams",   "");
86       }
87
88       virtual zypp::url::ParamMap
89       getQueryStringMap(zypp::url::EEncoding eflag) const
90       {
91         static const char * const keys[] = {
92           "attrs", "scope", "filter", "exts", NULL
93         };
94         zypp::url::ParamMap pmap;
95         zypp::url::ParamVec pvec( getQueryStringVec());
96         if( pvec.size() <= 4)
97         {
98           for(size_t i=0; i<pvec.size(); i++)
99           {
100             if(eflag == zypp::url::E_ENCODED)
101               pmap[keys[i]] = pvec[i];
102             else
103               pmap[keys[i]] = zypp::url::decode( pvec[i]);
104           }
105         }
106         else
107         {
108           ZYPP_THROW(url::UrlNotSupportedException(
109             "Invalid LDAP URL query string"
110           ));
111         }
112         return pmap;
113       }
114
115       virtual void
116       setQueryStringMap(const zypp::url::ParamMap &pmap)
117       {
118         static const char * const keys[] = {
119           "attrs", "scope", "filter", "exts", NULL
120         };
121
122         // remove psep ("?") from safe chars
123         std::string join_safe;
124         std::string safe(config("safe_querystr"));
125         std::string psep(config("psep_querystr"));
126         for(std::string::size_type i=0; i<safe.size(); i++)
127         {
128           if( psep.find(safe[i]) == std::string::npos)
129             join_safe.append(1, safe[i]);
130         }
131
132         zypp::url::ParamVec pvec(4);
133         zypp::url::ParamMap::const_iterator p;
134         for(p=pmap.begin(); p!=pmap.end(); ++p)
135         {
136           bool found=false;
137           for(size_t i=0; i<4; i++)
138           {
139             if(p->first == keys[i])
140             {
141               found=true;
142               pvec[i] = zypp::url::encode(p->second, join_safe);
143             }
144           }
145           if( !found)
146           {
147             ZYPP_THROW(url::UrlNotSupportedException(
148               "Invalid LDAP URL query parameter '" + p->first + "'"
149             ));
150           }
151         }
152         setQueryStringVec(pvec);
153       }
154     };
155
156
157     // ---------------------------------------------------------------
158     // FIXME: hmm..
159     class UrlByScheme
160     {
161     private:
162       typedef std::map<std::string,UrlRef> UrlBySchemeMap;
163       UrlBySchemeMap urlByScheme;
164
165     public:
166       UrlByScheme()
167       {
168         UrlRef ref;
169
170         // =====================================
171         ref.reset( new LDAPUrl());
172         addUrlByScheme("ldap", ref);
173         addUrlByScheme("ldaps", ref);
174
175
176         // =====================================
177         ref.reset( new UrlBase());
178         ref->config("with_authority",   "n");   // disallow host,...
179         ref->config("require_pathname", "m");   // path is mandatory
180         addUrlByScheme("hd",     ref);
181         addUrlByScheme("cd",     ref);
182         addUrlByScheme("dvd",    ref);
183         addUrlByScheme("dir",    ref);
184         addUrlByScheme("iso",    ref);
185
186         // don't show empty authority
187         ref->setViewOptions( zypp::url::ViewOption::DEFAULTS -
188                              zypp::url::ViewOption::EMPTY_AUTHORITY);
189         addUrlByScheme("mailto", ref);
190         addUrlByScheme("urn",    ref);
191
192         // RFC1738, 3.10: may contain a host
193         ref->config("with_authority",   "y");   // allow host,
194         ref->config("with_port",        "n");   // but no port,
195         ref->config("rx_username",      "");    // username or
196         ref->config("rx_password",      "");    // password ...
197         addUrlByScheme("file",   ref);
198
199         // =====================================
200         ref.reset( new UrlBase());
201         ref->config("require_host",     "m");   // host is mandatory
202         addUrlByScheme("nfs",    ref);
203         addUrlByScheme("smb",    ref);
204         addUrlByScheme("cifs",   ref);
205         addUrlByScheme("http",   ref);
206         addUrlByScheme("https",  ref);
207         ref->config("path_encode_slash2", "y"); // always encode 2. slash
208         addUrlByScheme("ftp",    ref);
209         addUrlByScheme("sftp",   ref);
210       }
211
212       bool
213       addUrlByScheme(const std::string &scheme,
214                      UrlRef            urlImpl)
215       {
216         if( urlImpl && urlImpl->isValidScheme(scheme))
217         {
218           UrlRef ref(urlImpl);
219           ref->clear();
220           urlByScheme[str::toLower(scheme)] = ref;
221           return true;
222         }
223         return false;
224       }
225
226       UrlRef
227       getUrlByScheme(const std::string &scheme) const
228       {
229         UrlBySchemeMap::const_iterator i(urlByScheme.find(str::toLower(scheme)));
230         if( i != urlByScheme.end())
231         {
232           return i->second;
233         }
234         return UrlRef();
235       }
236
237       bool
238       isRegisteredScheme(const std::string &scheme) const
239       {
240         return urlByScheme.find(str::toLower(scheme)) != urlByScheme.end();
241       }
242
243       UrlSchemes
244       getRegisteredSchemes() const
245       {
246         UrlBySchemeMap::const_iterator i(urlByScheme.begin());
247         UrlSchemes                     schemes;
248
249         schemes.reserve(urlByScheme.size());
250         for( ; i != urlByScheme.end(); ++i)
251         {
252           schemes.push_back(i->first);
253         }
254         return schemes;
255       }
256     };
257
258
259     // ---------------------------------------------------------------
260     UrlByScheme g_urlSchemeRepository;
261
262
263     //////////////////////////////////////////////////////////////////
264   } // anonymous namespace
265   ////////////////////////////////////////////////////////////////////
266
267
268   // -----------------------------------------------------------------
269   Url::~Url()
270   {
271   }
272
273
274   // -----------------------------------------------------------------
275   Url::Url()
276     : m_impl( new UrlBase())
277   {
278   }
279
280
281   // -----------------------------------------------------------------
282   Url::Url(const Url &url)
283     : m_impl( url.m_impl)
284   {
285     if( !m_impl)
286     {
287       ZYPP_THROW(url::UrlException(
288         "Unable to clone Url object"
289       ));
290     }
291   }
292
293
294   // -----------------------------------------------------------------
295   Url::Url(const zypp::url::UrlRef &url)
296     : m_impl( url)
297   {
298     if( !m_impl)
299     {
300       ZYPP_THROW(url::UrlException(
301         "Invalid empty Url reference"
302       ));
303     }
304   }
305
306
307   // -----------------------------------------------------------------
308   Url::Url(const std::string &encodedUrl)
309     : m_impl( parseUrl(encodedUrl))
310   {
311     if( !m_impl)
312     {
313       ZYPP_THROW(url::UrlParsingException(
314         "Unable to parse Url components"
315       ));
316     }
317   }
318
319
320   // -----------------------------------------------------------------
321   Url&
322   Url::operator = (const std::string &encodedUrl)
323   {
324     UrlRef url( parseUrl(encodedUrl));
325     if( !url)
326     {
327       ZYPP_THROW(url::UrlParsingException(
328         "Unable to parse Url components"
329       ));
330     }
331     m_impl = url;
332     return *this;
333   }
334
335
336   // -----------------------------------------------------------------
337   Url&
338   Url::operator = (const Url &url)
339   {
340     m_impl = url.m_impl;
341     return *this;
342   }
343
344
345   // -----------------------------------------------------------------
346   // static
347   bool
348   Url::registerScheme(const std::string &scheme,
349                       UrlRef            urlImpl)
350   {
351     return g_urlSchemeRepository.addUrlByScheme(scheme, urlImpl);
352   }
353
354
355   // -----------------------------------------------------------------
356   // static
357   UrlRef
358   Url::parseUrl(const std::string &encodedUrl)
359   {
360     UrlRef      url;
361     str::smatch out;
362     bool        ret = false;
363
364     try
365     {
366       str::regex  rex(RX_SPLIT_URL);
367       ret = str::regex_match(encodedUrl, out, rex);
368     }
369     catch( ... )
370     {}
371
372     if(ret && out.size() == 10)
373     {
374       url = g_urlSchemeRepository.getUrlByScheme(out[2].str());
375       if( !url)
376       {
377         url.reset( new UrlBase());
378       }
379       url->init(out[2].str(),
380                 out[4].str(),
381                 out[5].str(),
382                 out[7].str(),
383                 out[9].str());
384     }
385     return url;
386   }
387
388
389   // -----------------------------------------------------------------
390   // static
391   zypp::url::UrlSchemes
392   Url::getRegisteredSchemes()
393   {
394     return g_urlSchemeRepository.getRegisteredSchemes();
395   }
396
397
398   // -----------------------------------------------------------------
399   // static
400   bool
401   Url::isRegisteredScheme(const std::string &scheme)
402   {
403     return g_urlSchemeRepository.isRegisteredScheme(scheme);
404   }
405
406
407   // -----------------------------------------------------------------
408   zypp::url::UrlSchemes
409   Url::getKnownSchemes() const
410   {
411     return m_impl->getKnownSchemes();
412   }
413
414
415   // -----------------------------------------------------------------
416   bool
417   Url::isValidScheme(const std::string &scheme) const
418   {
419     return m_impl->isValidScheme(scheme);
420   }
421
422
423   // -----------------------------------------------------------------
424   bool
425   Url::isValid() const
426   {
427     return m_impl->isValid();
428   }
429
430
431   // -----------------------------------------------------------------
432   std::string
433   Url::asString() const
434   {
435     return m_impl->asString();
436   }
437
438
439   // -----------------------------------------------------------------
440   std::string
441   Url::asCompleteString() const
442   {
443     // make sure, all url components are included;
444     // regardless of the current configuration...
445     ViewOptions opts(getViewOptions() +
446                      ViewOption::WITH_SCHEME +
447                      ViewOption::WITH_USERNAME +
448                      ViewOption::WITH_PASSWORD +
449                      ViewOption::WITH_HOST +
450                      ViewOption::WITH_PORT +
451                      ViewOption::WITH_PATH_NAME +
452                      ViewOption::WITH_PATH_PARAMS +
453                      ViewOption::WITH_QUERY_STR +
454                      ViewOption::WITH_FRAGMENT);
455     return m_impl->asString(opts);
456   }
457
458
459   // -----------------------------------------------------------------
460   std::string
461   Url::asString(const ViewOptions &opts) const
462   {
463     return m_impl->asString(opts);
464   }
465
466
467   // -----------------------------------------------------------------
468   std::string
469   Url::getScheme() const
470   {
471     return m_impl->getScheme();
472   }
473
474
475   // -----------------------------------------------------------------
476   std::string
477   Url::getAuthority() const
478   {
479     return m_impl->getAuthority();
480   }
481
482   // -----------------------------------------------------------------
483   std::string
484   Url::getPathData() const
485   {
486     return m_impl->getPathData();
487   }
488
489
490   // -----------------------------------------------------------------
491   std::string
492   Url::getQueryString() const
493   {
494     return m_impl->getQueryString();
495   }
496
497
498   // -----------------------------------------------------------------
499   std::string
500   Url::getFragment(zypp::url::EEncoding eflag) const
501   {
502     return m_impl->getFragment(eflag);
503   }
504
505
506   // -----------------------------------------------------------------
507   std::string
508   Url::getUsername(EEncoding eflag) const
509   {
510     return m_impl->getUsername(eflag);
511   }
512
513
514   // -----------------------------------------------------------------
515   std::string
516   Url::getPassword(EEncoding eflag) const
517   {
518     return m_impl->getPassword(eflag);
519   }
520
521
522   // -----------------------------------------------------------------
523   std::string
524   Url::getHost(EEncoding eflag) const
525   {
526     return m_impl->getHost(eflag);
527   }
528
529
530   // -----------------------------------------------------------------
531   std::string
532   Url::getPort() const
533   {
534     return m_impl->getPort();
535   }
536
537
538   // -----------------------------------------------------------------
539   std::string
540   Url::getPathName(EEncoding eflag) const
541   {
542     return m_impl->getPathName(eflag);
543   }
544
545
546   // -----------------------------------------------------------------
547   std::string
548   Url::getPathParams() const
549   {
550     return m_impl->getPathParams();
551   }
552
553
554   // -----------------------------------------------------------------
555   zypp::url::ParamVec
556   Url::getPathParamsVec() const
557   {
558     return m_impl->getPathParamsVec();
559   }
560
561
562   // -----------------------------------------------------------------
563   zypp::url::ParamMap
564   Url::getPathParamsMap(EEncoding eflag) const
565   {
566     return m_impl->getPathParamsMap(eflag);
567   }
568
569
570   // -----------------------------------------------------------------
571   std::string
572   Url::getPathParam(const std::string &param, EEncoding eflag) const
573   {
574     return m_impl->getPathParam(param, eflag);
575   }
576
577
578   // -----------------------------------------------------------------
579   zypp::url::ParamVec
580   Url::getQueryStringVec() const
581   {
582     return m_impl->getQueryStringVec();
583   }
584
585
586   // -----------------------------------------------------------------
587   zypp::url::ParamMap
588   Url::getQueryStringMap(EEncoding eflag) const
589   {
590     return m_impl->getQueryStringMap(eflag);
591   }
592
593
594   // -----------------------------------------------------------------
595   std::string
596   Url::getQueryParam(const std::string &param, EEncoding eflag) const
597   {
598     return m_impl->getQueryParam(param, eflag);
599   }
600
601
602   // -----------------------------------------------------------------
603   void
604   Url::setScheme(const std::string &scheme)
605   {
606     if(scheme == m_impl->getScheme())
607     {
608       return;
609     }
610     if( m_impl->isKnownScheme(scheme))
611     {
612       m_impl->setScheme(scheme);
613       return;
614     }
615
616     UrlRef url = g_urlSchemeRepository.getUrlByScheme(scheme);
617     if( !url)
618     {
619       url.reset( new UrlBase());
620     }
621     url->init(
622       scheme,
623       m_impl->getAuthority(),
624       m_impl->getPathData(),
625       m_impl->getQueryString(),
626       m_impl->getFragment(zypp::url::E_ENCODED)
627     );
628     m_impl = url;
629   }
630
631
632   // -----------------------------------------------------------------
633   void
634   Url::setAuthority(const std::string &authority)
635   {
636     m_impl->setAuthority(authority);
637   }
638
639
640   // -----------------------------------------------------------------
641   void
642   Url::setPathData(const std::string &pathdata)
643   {
644     m_impl->setPathData(pathdata);
645   }
646
647
648   // -----------------------------------------------------------------
649   void
650   Url::setQueryString(const std::string &querystr)
651   {
652     m_impl->setQueryString(querystr);
653   }
654
655
656   // -----------------------------------------------------------------
657   void
658   Url::setFragment(const std::string &fragment, EEncoding eflag)
659   {
660     m_impl->setFragment(fragment, eflag);
661   }
662
663
664   // -----------------------------------------------------------------
665   void
666   Url::setUsername(const std::string &user,
667                    EEncoding         eflag)
668   {
669     m_impl->setUsername(user, eflag);
670   }
671
672
673   // -----------------------------------------------------------------
674   void
675   Url::setPassword(const std::string &pass,
676                    EEncoding         eflag)
677   {
678     m_impl->setPassword(pass, eflag);
679   }
680
681
682   // -----------------------------------------------------------------
683   void
684   Url::setHost(const std::string &host)
685   {
686     m_impl->setHost(host);
687   }
688
689
690   // -----------------------------------------------------------------
691   void
692   Url::setPort(const std::string &port)
693   {
694     m_impl->setPort(port);
695   }
696
697
698   // -----------------------------------------------------------------
699   void
700   Url::setPathName(const std::string &path,
701                    EEncoding         eflag)
702   {
703     m_impl->setPathName(path, eflag);
704   }
705
706
707   // -----------------------------------------------------------------
708   void
709   Url::setPathParams(const std::string &params)
710   {
711     m_impl->setPathParams(params);
712   }
713
714
715   // -----------------------------------------------------------------
716   void
717   Url::setPathParamsVec(const zypp::url::ParamVec &pvec)
718   {
719     m_impl->setPathParamsVec(pvec);
720   }
721
722
723   // -----------------------------------------------------------------
724   void
725   Url::setPathParamsMap(const zypp::url::ParamMap &pmap)
726   {
727     m_impl->setPathParamsMap(pmap);
728   }
729
730
731   // -----------------------------------------------------------------
732   void
733   Url::setPathParam(const std::string &param, const std::string &value)
734   {
735     m_impl->setPathParam(param, value);
736   }
737
738
739   // -----------------------------------------------------------------
740   void
741   Url::setQueryStringVec(const zypp::url::ParamVec &pvec)
742   {
743     m_impl->setQueryStringVec(pvec);
744   }
745
746
747   // -----------------------------------------------------------------
748   void
749   Url::setQueryStringMap(const zypp::url::ParamMap &pmap)
750   {
751     m_impl->setQueryStringMap(pmap);
752   }
753
754   // -----------------------------------------------------------------
755   void
756   Url::setQueryParam(const std::string &param, const std::string &value)
757   {
758     m_impl->setQueryParam(param, value);
759   }
760
761   // -----------------------------------------------------------------
762   ViewOptions
763   Url::getViewOptions() const
764   {
765     return m_impl->getViewOptions();
766   }
767
768   // -----------------------------------------------------------------
769   void
770   Url::setViewOptions(const ViewOptions &vopts)
771   {
772     m_impl->setViewOptions(vopts);
773   }
774
775   // -----------------------------------------------------------------
776   std::ostream & operator<<( std::ostream & str, const Url & url )
777   {
778     return str << url.asString();
779   }
780
781
782   ////////////////////////////////////////////////////////////////////
783 } // namespace zypp
784 //////////////////////////////////////////////////////////////////////
785 /*
786 ** vim: set ts=2 sts=2 sw=2 ai et:
787 */