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