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