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