1eede89859901c17fba1ad89ddb2bc3b068d9d96
[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         ref->config("with_authority",   "n");   // disallow host,...
185         ref->config("require_pathname", "m");   // path is mandatory
186         addUrlByScheme("hd",     ref);
187         addUrlByScheme("cd",     ref);
188         addUrlByScheme("dvd",    ref);
189         addUrlByScheme("dir",    ref);
190         addUrlByScheme("iso",    ref);
191
192         // don't show empty authority
193         ref->setViewOptions( zypp::url::ViewOption::DEFAULTS -
194                              zypp::url::ViewOption::EMPTY_AUTHORITY);
195         addUrlByScheme("mailto", ref);
196         addUrlByScheme("urn",    ref);
197         addUrlByScheme("plugin", ref);  // zypp plugable media handler:
198
199         // RFC1738, 3.10: may contain a host
200         ref->config("with_authority",   "y");   // allow host,
201         ref->config("with_port",        "n");   // but no port,
202         ref->config("rx_username",      "");    // username or
203         ref->config("rx_password",      "");    // password ...
204         addUrlByScheme("file",   ref);
205
206         // =====================================
207         ref.reset( new UrlBase());
208         ref->config("require_host",     "m");   // host is mandatory
209         addUrlByScheme("nfs",    ref);
210         addUrlByScheme("nfs4",   ref);
211         addUrlByScheme("smb",    ref);
212         addUrlByScheme("cifs",   ref);
213         addUrlByScheme("http",   ref);
214         addUrlByScheme("https",  ref);
215         ref->config("path_encode_slash2", "y"); // always encode 2. slash
216         addUrlByScheme("ftp",    ref);
217         addUrlByScheme("sftp",   ref);
218         addUrlByScheme("tftp",   ref);
219       }
220
221       bool
222       addUrlByScheme(const std::string &scheme,
223                      UrlRef            urlImpl)
224       {
225         if( urlImpl && urlImpl->isValidScheme(scheme))
226         {
227           UrlRef ref(urlImpl);
228           ref->clear();
229           urlByScheme[str::toLower(scheme)] = ref;
230           return true;
231         }
232         return false;
233       }
234
235       UrlRef
236       getUrlByScheme(const std::string &scheme) const
237       {
238         UrlBySchemeMap::const_iterator i(urlByScheme.find(str::toLower(scheme)));
239         if( i != urlByScheme.end())
240         {
241           return i->second;
242         }
243         return UrlRef();
244       }
245
246       bool
247       isRegisteredScheme(const std::string &scheme) const
248       {
249         return urlByScheme.find(str::toLower(scheme)) != urlByScheme.end();
250       }
251
252       UrlSchemes
253       getRegisteredSchemes() const
254       {
255         UrlBySchemeMap::const_iterator i(urlByScheme.begin());
256         UrlSchemes                     schemes;
257
258         schemes.reserve(urlByScheme.size());
259         for( ; i != urlByScheme.end(); ++i)
260         {
261           schemes.push_back(i->first);
262         }
263         return schemes;
264       }
265     };
266
267
268     // ---------------------------------------------------------------
269     UrlByScheme & g_urlSchemeRepository()
270     {
271       static UrlByScheme _v;
272       return _v;
273     }
274
275     //////////////////////////////////////////////////////////////////
276   } // anonymous namespace
277   ////////////////////////////////////////////////////////////////////
278
279
280   // -----------------------------------------------------------------
281   Url::~Url()
282   {
283   }
284
285
286   // -----------------------------------------------------------------
287   Url::Url()
288     : m_impl( new UrlBase())
289   {
290   }
291
292
293   // -----------------------------------------------------------------
294   Url::Url(const Url &url)
295     : m_impl( url.m_impl)
296   {
297     if( !m_impl)
298     {
299       ZYPP_THROW(url::UrlException(
300         _("Unable to clone Url object")
301       ));
302     }
303   }
304
305
306   // -----------------------------------------------------------------
307   Url::Url(const zypp::url::UrlRef &url)
308     : m_impl( url)
309   {
310     if( !m_impl)
311     {
312       ZYPP_THROW(url::UrlException(
313         _("Invalid empty Url object reference")
314       ));
315     }
316   }
317
318
319   // -----------------------------------------------------------------
320   Url::Url(const std::string &encodedUrl)
321     : m_impl( parseUrl(encodedUrl))
322   {
323     if( !m_impl)
324     {
325       ZYPP_THROW(url::UrlParsingException(
326         _("Unable to parse Url components")
327       ));
328     }
329   }
330
331
332   // -----------------------------------------------------------------
333   Url&
334   Url::operator = (const std::string &encodedUrl)
335   {
336     UrlRef url( parseUrl(encodedUrl));
337     if( !url)
338     {
339       ZYPP_THROW(url::UrlParsingException(
340         _("Unable to parse Url components")
341       ));
342     }
343     m_impl = url;
344     return *this;
345   }
346
347
348   // -----------------------------------------------------------------
349   Url&
350   Url::operator = (const Url &url)
351   {
352     m_impl = url.m_impl;
353     return *this;
354   }
355
356
357   // -----------------------------------------------------------------
358   // static
359   bool
360   Url::registerScheme(const std::string &scheme,
361                       UrlRef            urlImpl)
362   {
363     return g_urlSchemeRepository().addUrlByScheme(scheme, urlImpl);
364   }
365
366
367   // -----------------------------------------------------------------
368   // static
369   UrlRef
370   Url::parseUrl(const std::string &encodedUrl)
371   {
372     UrlRef      url;
373     str::smatch out;
374     bool        ret = false;
375
376     try
377     {
378       str::regex  rex(RX_SPLIT_URL);
379       ret = str::regex_match(encodedUrl, out, rex);
380     }
381     catch( ... )
382     {}
383
384     if(ret && out.size() == 6)
385     {
386       std::string scheme = out[1];
387       if (scheme.size() > 1)
388         scheme = scheme.substr(0, scheme.size()-1);
389       std::string authority = out[2];
390       if (authority.size() >= 2)
391         authority = authority.substr(2);
392       std::string query = out[4];
393       if (query.size() > 1)
394         query = query.substr(1);
395       std::string fragment = out[5];
396       if (fragment.size() > 1)
397         fragment = fragment.substr(1);
398
399       url = g_urlSchemeRepository().getUrlByScheme(scheme);
400       if( !url)
401       {
402         url.reset( new UrlBase());
403       }
404       url->init(scheme, authority, out[3],
405                 query, fragment);
406     }
407     return url;
408   }
409
410
411   // -----------------------------------------------------------------
412   // static
413   zypp::url::UrlSchemes
414   Url::getRegisteredSchemes()
415   {
416     return g_urlSchemeRepository().getRegisteredSchemes();
417   }
418
419
420   // -----------------------------------------------------------------
421   // static
422   bool
423   Url::isRegisteredScheme(const std::string &scheme)
424   {
425     return g_urlSchemeRepository().isRegisteredScheme(scheme);
426   }
427
428
429   // -----------------------------------------------------------------
430   zypp::url::UrlSchemes
431   Url::getKnownSchemes() const
432   {
433     return m_impl->getKnownSchemes();
434   }
435
436
437   // -----------------------------------------------------------------
438   bool
439   Url::isValidScheme(const std::string &scheme) const
440   {
441     return m_impl->isValidScheme(scheme);
442   }
443
444
445   ///////////////////////////////////////////////////////////////////
446   namespace
447   {
448     inline bool isInList( const char ** begin_r, const char ** end_r, const std::string & scheme_r )
449     {
450       for ( ; begin_r != end_r; ++begin_r )
451         if ( scheme_r == *begin_r )
452           return true;
453       return false;
454     }
455   }
456   bool Url::schemeIsLocal( const std::string & scheme_r )
457   {
458     static const char * val[] = { "cd", "dvd", "dir", "hd", "iso", "file" };
459     return isInList( arrayBegin(val), arrayEnd(val), scheme_r );
460   }
461
462   bool Url::schemeIsRemote( const std::string & scheme_r )
463   {
464     static const char * val[] = { "http", "https", "nfs", "nfs4", "smb", "cifs", "ftp", "sftp", "tftp" };
465     return isInList( arrayBegin(val), arrayEnd(val), scheme_r );
466   }
467
468   bool Url::schemeIsVolatile( const std::string & scheme_r )
469   {
470     static const char * val[] = { "cd", "dvd" };
471     return isInList( arrayBegin(val), arrayEnd(val), scheme_r );
472   }
473
474   bool Url::schemeIsDownloading( const std::string & scheme_r )
475   {
476     static const char * val[] = { "http", "https", "ftp", "sftp", "tftp" };
477     return isInList( arrayBegin(val), arrayEnd(val), scheme_r );
478   }
479   ///////////////////////////////////////////////////////////////////
480
481   // -----------------------------------------------------------------
482   bool
483   Url::isValid() const
484   {
485     return m_impl->isValid();
486   }
487
488
489   // -----------------------------------------------------------------
490   std::string
491   Url::asString() const
492   {
493     return m_impl->asString();
494   }
495
496
497   // -----------------------------------------------------------------
498   std::string
499   Url::asCompleteString() const
500   {
501     // make sure, all url components are included;
502     // regardless of the current configuration...
503     ViewOptions opts(getViewOptions() +
504                      ViewOption::WITH_SCHEME +
505                      ViewOption::WITH_USERNAME +
506                      ViewOption::WITH_PASSWORD +
507                      ViewOption::WITH_HOST +
508                      ViewOption::WITH_PORT +
509                      ViewOption::WITH_PATH_NAME +
510                      ViewOption::WITH_PATH_PARAMS +
511                      ViewOption::WITH_QUERY_STR +
512                      ViewOption::WITH_FRAGMENT);
513     return m_impl->asString(opts);
514   }
515
516
517   // -----------------------------------------------------------------
518   std::string
519   Url::asString(const ViewOptions &opts) const
520   {
521     return m_impl->asString(opts);
522   }
523
524
525   // -----------------------------------------------------------------
526   std::string
527   Url::getScheme() const
528   {
529     return m_impl->getScheme();
530   }
531
532
533   // -----------------------------------------------------------------
534   std::string
535   Url::getAuthority() const
536   {
537     return m_impl->getAuthority();
538   }
539
540   // -----------------------------------------------------------------
541   std::string
542   Url::getPathData() const
543   {
544     return m_impl->getPathData();
545   }
546
547
548   // -----------------------------------------------------------------
549   std::string
550   Url::getQueryString() const
551   {
552     return m_impl->getQueryString();
553   }
554
555
556   // -----------------------------------------------------------------
557   std::string
558   Url::getFragment(zypp::url::EEncoding eflag) const
559   {
560     return m_impl->getFragment(eflag);
561   }
562
563
564   // -----------------------------------------------------------------
565   std::string
566   Url::getUsername(EEncoding eflag) const
567   {
568     return m_impl->getUsername(eflag);
569   }
570
571
572   // -----------------------------------------------------------------
573   std::string
574   Url::getPassword(EEncoding eflag) const
575   {
576     return m_impl->getPassword(eflag);
577   }
578
579
580   // -----------------------------------------------------------------
581   std::string
582   Url::getHost(EEncoding eflag) const
583   {
584     return m_impl->getHost(eflag);
585   }
586
587
588   // -----------------------------------------------------------------
589   std::string
590   Url::getPort() const
591   {
592     return m_impl->getPort();
593   }
594
595
596   // -----------------------------------------------------------------
597   std::string
598   Url::getPathName(EEncoding eflag) const
599   {
600     return m_impl->getPathName(eflag);
601   }
602
603
604   // -----------------------------------------------------------------
605   std::string
606   Url::getPathParams() const
607   {
608     return m_impl->getPathParams();
609   }
610
611
612   // -----------------------------------------------------------------
613   zypp::url::ParamVec
614   Url::getPathParamsVec() const
615   {
616     return m_impl->getPathParamsVec();
617   }
618
619
620   // -----------------------------------------------------------------
621   zypp::url::ParamMap
622   Url::getPathParamsMap(EEncoding eflag) const
623   {
624     return m_impl->getPathParamsMap(eflag);
625   }
626
627
628   // -----------------------------------------------------------------
629   std::string
630   Url::getPathParam(const std::string &param, EEncoding eflag) const
631   {
632     return m_impl->getPathParam(param, eflag);
633   }
634
635
636   // -----------------------------------------------------------------
637   zypp::url::ParamVec
638   Url::getQueryStringVec() const
639   {
640     return m_impl->getQueryStringVec();
641   }
642
643
644   // -----------------------------------------------------------------
645   zypp::url::ParamMap
646   Url::getQueryStringMap(EEncoding eflag) const
647   {
648     return m_impl->getQueryStringMap(eflag);
649   }
650
651
652   // -----------------------------------------------------------------
653   std::string
654   Url::getQueryParam(const std::string &param, EEncoding eflag) const
655   {
656     return m_impl->getQueryParam(param, eflag);
657   }
658
659
660   // -----------------------------------------------------------------
661   void
662   Url::setScheme(const std::string &scheme)
663   {
664     if(scheme == m_impl->getScheme())
665     {
666       return;
667     }
668     if( m_impl->isKnownScheme(scheme))
669     {
670       m_impl->setScheme(scheme);
671       return;
672     }
673
674     UrlRef url = g_urlSchemeRepository().getUrlByScheme(scheme);
675     if( !url)
676     {
677       url.reset( new UrlBase());
678     }
679     url->init(
680       scheme,
681       m_impl->getAuthority(),
682       m_impl->getPathData(),
683       m_impl->getQueryString(),
684       m_impl->getFragment(zypp::url::E_ENCODED)
685     );
686     m_impl = url;
687   }
688
689
690   // -----------------------------------------------------------------
691   void
692   Url::setAuthority(const std::string &authority)
693   {
694     m_impl->setAuthority(authority);
695   }
696
697
698   // -----------------------------------------------------------------
699   void
700   Url::setPathData(const std::string &pathdata)
701   {
702     m_impl->setPathData(pathdata);
703   }
704
705
706   // -----------------------------------------------------------------
707   void
708   Url::setQueryString(const std::string &querystr)
709   {
710     m_impl->setQueryString(querystr);
711   }
712
713
714   // -----------------------------------------------------------------
715   void
716   Url::setFragment(const std::string &fragment, EEncoding eflag)
717   {
718     m_impl->setFragment(fragment, eflag);
719   }
720
721
722   // -----------------------------------------------------------------
723   void
724   Url::setUsername(const std::string &user,
725                    EEncoding         eflag)
726   {
727     m_impl->setUsername(user, eflag);
728   }
729
730
731   // -----------------------------------------------------------------
732   void
733   Url::setPassword(const std::string &pass,
734                    EEncoding         eflag)
735   {
736     m_impl->setPassword(pass, eflag);
737   }
738
739
740   // -----------------------------------------------------------------
741   void
742   Url::setHost(const std::string &host)
743   {
744     m_impl->setHost(host);
745   }
746
747
748   // -----------------------------------------------------------------
749   void
750   Url::setPort(const std::string &port)
751   {
752     m_impl->setPort(port);
753   }
754
755
756   // -----------------------------------------------------------------
757   void
758   Url::setPathName(const std::string &path,
759                    EEncoding         eflag)
760   {
761     m_impl->setPathName(path, eflag);
762   }
763
764   void
765   Url::setPathName(const Pathname &path,
766                    EEncoding         eflag)
767   {
768     m_impl->setPathName(path.asString(), eflag);
769   }
770
771   void
772   Url::setPathName(const char *path,
773                    EEncoding         eflag)
774   {
775     m_impl->setPathName(path, eflag);
776   }
777
778   // -----------------------------------------------------------------
779   void
780   Url::setPathParams(const std::string &params)
781   {
782     m_impl->setPathParams(params);
783   }
784
785
786   // -----------------------------------------------------------------
787   void
788   Url::setPathParamsVec(const zypp::url::ParamVec &pvec)
789   {
790     m_impl->setPathParamsVec(pvec);
791   }
792
793
794   // -----------------------------------------------------------------
795   void
796   Url::setPathParamsMap(const zypp::url::ParamMap &pmap)
797   {
798     m_impl->setPathParamsMap(pmap);
799   }
800
801
802   // -----------------------------------------------------------------
803   void
804   Url::setPathParam(const std::string &param, const std::string &value)
805   {
806     m_impl->setPathParam(param, value);
807   }
808
809
810   // -----------------------------------------------------------------
811   void
812   Url::setQueryStringVec(const zypp::url::ParamVec &pvec)
813   {
814     m_impl->setQueryStringVec(pvec);
815   }
816
817
818   // -----------------------------------------------------------------
819   void
820   Url::setQueryStringMap(const zypp::url::ParamMap &pmap)
821   {
822     m_impl->setQueryStringMap(pmap);
823   }
824
825   // -----------------------------------------------------------------
826   void
827   Url::setQueryParam(const std::string &param, const std::string &value)
828   {
829     m_impl->setQueryParam(param, value);
830   }
831
832   // -----------------------------------------------------------------
833   void
834   Url::delQueryParam(const std::string &param)
835   {
836     m_impl->delQueryParam(param);
837   }
838
839   // -----------------------------------------------------------------
840   ViewOptions
841   Url::getViewOptions() const
842   {
843     return m_impl->getViewOptions();
844   }
845
846   // -----------------------------------------------------------------
847   void
848   Url::setViewOptions(const ViewOptions &vopts)
849   {
850     m_impl->setViewOptions(vopts);
851   }
852
853   // -----------------------------------------------------------------
854   std::ostream & operator<<( std::ostream & str, const Url & url )
855   {
856     return str << url.asString();
857   }
858
859   bool operator<( const Url &lhs, const Url &rhs )
860   {
861     return (lhs.asCompleteString() < rhs.asCompleteString());
862   }
863
864   bool operator==( const Url &lhs, const Url &rhs )
865   {
866     return (lhs.asCompleteString() == rhs.asCompleteString());
867   }
868
869   bool operator!=( const Url &lhs, const Url &rhs )
870   {
871     return (lhs.asCompleteString() != rhs.asCompleteString());
872   }
873
874   ////////////////////////////////////////////////////////////////////
875 } // namespace zypp
876 //////////////////////////////////////////////////////////////////////
877 /*
878 ** vim: set ts=2 sts=2 sw=2 ai et:
879 */