libzypp  10.5.0
Url.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00013 #include <zypp/Url.h>
00014 #include <zypp/base/Gettext.h>
00015 #include <zypp/base/String.h>
00016 #include <zypp/base/Regex.h>
00017 #include <stdexcept>
00018 #include <iostream>
00019 
00020 
00022 namespace zypp
00023 { 
00024 
00025 
00026   using namespace zypp::url;
00027 
00028 
00029   // -----------------------------------------------------------------
00030   /*
00031    * url       = [scheme:] [//authority] /path [?query] [#fragment]
00032    */
00033   #define RX_SPLIT_URL                       "^([^:/?#]+:|)" \
00034                                              "(//[^/?#]*|)"  \
00035                                              "([^?#]*)"        \
00036                                              "([?][^#]*|)"   \
00037                                              "(#.*|)"
00038 
00039 
00041   namespace
00042   { 
00043 
00044 
00045     // ---------------------------------------------------------------
00046     class LDAPUrl: public UrlBase
00047     {
00048     public:
00049       LDAPUrl(): UrlBase()
00050       {
00051         configure();
00052       }
00053 
00054       LDAPUrl(const LDAPUrl &url): UrlBase(url)
00055       {}
00056 
00057       virtual UrlBase *
00058       clone() const
00059       {
00060         return new LDAPUrl(*this);
00061       }
00062 
00063       virtual UrlSchemes
00064       getKnownSchemes() const
00065       {
00066         UrlSchemes schemes(2);
00067         schemes[0] = "ldap";
00068         schemes[1] = "ldaps";
00069         return schemes;
00070       }
00071 
00072       virtual void
00073       configure()
00074       {
00075         config("sep_pathparams",  "");
00076 
00077         config("psep_querystr",   "?");
00078         config("vsep_querystr",   "");
00079 
00080         // host is required (isValid=>false)
00081         // but not mandatory (see RFC 2255),
00082         // that is, accept empty host.
00083         config("require_host",    "y");
00084 
00085         // not allowed here
00086         config("rx_username",     "");
00087         config("rx_password",     "");
00088         config("rx_fragment",     "");
00089         config("rx_pathparams",   "");
00090       }
00091 
00092       virtual zypp::url::ParamMap
00093       getQueryStringMap(zypp::url::EEncoding eflag) const
00094       {
00095         static const char * const keys[] = {
00096           "attrs", "scope", "filter", "exts", NULL
00097         };
00098         zypp::url::ParamMap pmap;
00099         zypp::url::ParamVec pvec( getQueryStringVec());
00100         if( pvec.size() <= 4)
00101         {
00102           for(size_t i=0; i<pvec.size(); i++)
00103           {
00104             if(eflag == zypp::url::E_ENCODED)
00105               pmap[keys[i]] = pvec[i];
00106             else
00107               pmap[keys[i]] = zypp::url::decode( pvec[i]);
00108           }
00109         }
00110         else
00111         {
00112           ZYPP_THROW(url::UrlNotSupportedException(
00113             _("Invalid LDAP URL query string")
00114           ));
00115         }
00116         return pmap;
00117       }
00118 
00119       virtual void
00120       setQueryStringMap(const zypp::url::ParamMap &pmap)
00121       {
00122         static const char * const keys[] = {
00123           "attrs", "scope", "filter", "exts", NULL
00124         };
00125 
00126         // remove psep ("?") from safe chars
00127         std::string join_safe;
00128         std::string safe(config("safe_querystr"));
00129         std::string psep(config("psep_querystr"));
00130         for(std::string::size_type i=0; i<safe.size(); i++)
00131         {
00132           if( psep.find(safe[i]) == std::string::npos)
00133             join_safe.append(1, safe[i]);
00134         }
00135 
00136         zypp::url::ParamVec pvec(4);
00137         zypp::url::ParamMap::const_iterator p;
00138         for(p=pmap.begin(); p!=pmap.end(); ++p)
00139         {
00140           bool found=false;
00141           for(size_t i=0; i<4; i++)
00142           {
00143             if(p->first == keys[i])
00144             {
00145               found=true;
00146               pvec[i] = zypp::url::encode(p->second, join_safe);
00147             }
00148           }
00149           if( !found)
00150           {
00151             ZYPP_THROW(url::UrlNotSupportedException(
00152               str::form(_("Invalid LDAP URL query parameter '%s'"),
00153                           p->first.c_str())
00154             ));
00155           }
00156         }
00157         setQueryStringVec(pvec);
00158       }
00159     };
00160 
00161 
00162     // ---------------------------------------------------------------
00163     // FIXME: hmm..
00164     class UrlByScheme
00165     {
00166     private:
00167       typedef std::map<std::string,UrlRef> UrlBySchemeMap;
00168       UrlBySchemeMap urlByScheme;
00169 
00170     public:
00171       UrlByScheme()
00172       {
00173         UrlRef ref;
00174 
00175         // =====================================
00176         ref.reset( new LDAPUrl());
00177         addUrlByScheme("ldap", ref);
00178         addUrlByScheme("ldaps", ref);
00179 
00180 
00181         // =====================================
00182         ref.reset( new UrlBase());
00183         ref->config("with_authority",   "n");   // disallow host,...
00184         ref->config("require_pathname", "m");   // path is mandatory
00185         addUrlByScheme("hd",     ref);
00186         addUrlByScheme("cd",     ref);
00187         addUrlByScheme("dvd",    ref);
00188         addUrlByScheme("dir",    ref);
00189         addUrlByScheme("iso",    ref);
00190 
00191         // don't show empty authority
00192         ref->setViewOptions( zypp::url::ViewOption::DEFAULTS -
00193                              zypp::url::ViewOption::EMPTY_AUTHORITY);
00194         addUrlByScheme("mailto", ref);
00195         addUrlByScheme("urn",    ref);
00196         addUrlByScheme("plugin", ref);  // zypp plugable media handler:
00197 
00198         // RFC1738, 3.10: may contain a host
00199         ref->config("with_authority",   "y");   // allow host,
00200         ref->config("with_port",        "n");   // but no port,
00201         ref->config("rx_username",      "");    // username or
00202         ref->config("rx_password",      "");    // password ...
00203         addUrlByScheme("file",   ref);
00204 
00205         // =====================================
00206         ref.reset( new UrlBase());
00207         ref->config("require_host",     "m");   // host is mandatory
00208         addUrlByScheme("nfs",    ref);
00209         addUrlByScheme("nfs4",   ref);
00210         addUrlByScheme("smb",    ref);
00211         addUrlByScheme("cifs",   ref);
00212         addUrlByScheme("http",   ref);
00213         addUrlByScheme("https",  ref);
00214         ref->config("path_encode_slash2", "y"); // always encode 2. slash
00215         addUrlByScheme("ftp",    ref);
00216         addUrlByScheme("sftp",   ref);
00217       }
00218 
00219       bool
00220       addUrlByScheme(const std::string &scheme,
00221                      UrlRef            urlImpl)
00222       {
00223         if( urlImpl && urlImpl->isValidScheme(scheme))
00224         {
00225           UrlRef ref(urlImpl);
00226           ref->clear();
00227           urlByScheme[str::toLower(scheme)] = ref;
00228           return true;
00229         }
00230         return false;
00231       }
00232 
00233       UrlRef
00234       getUrlByScheme(const std::string &scheme) const
00235       {
00236         UrlBySchemeMap::const_iterator i(urlByScheme.find(str::toLower(scheme)));
00237         if( i != urlByScheme.end())
00238         {
00239           return i->second;
00240         }
00241         return UrlRef();
00242       }
00243 
00244       bool
00245       isRegisteredScheme(const std::string &scheme) const
00246       {
00247         return urlByScheme.find(str::toLower(scheme)) != urlByScheme.end();
00248       }
00249 
00250       UrlSchemes
00251       getRegisteredSchemes() const
00252       {
00253         UrlBySchemeMap::const_iterator i(urlByScheme.begin());
00254         UrlSchemes                     schemes;
00255 
00256         schemes.reserve(urlByScheme.size());
00257         for( ; i != urlByScheme.end(); ++i)
00258         {
00259           schemes.push_back(i->first);
00260         }
00261         return schemes;
00262       }
00263     };
00264 
00265 
00266     // ---------------------------------------------------------------
00267     UrlByScheme & g_urlSchemeRepository()
00268     {
00269       static UrlByScheme _v;
00270       return _v;
00271     }
00272 
00274   } // anonymous namespace
00276 
00277 
00278   // -----------------------------------------------------------------
00279   Url::~Url()
00280   {
00281   }
00282 
00283 
00284   // -----------------------------------------------------------------
00285   Url::Url()
00286     : m_impl( new UrlBase())
00287   {
00288   }
00289 
00290 
00291   // -----------------------------------------------------------------
00292   Url::Url(const Url &url)
00293     : m_impl( url.m_impl)
00294   {
00295     if( !m_impl)
00296     {
00297       ZYPP_THROW(url::UrlException(
00298         _("Unable to clone Url object")
00299       ));
00300     }
00301   }
00302 
00303 
00304   // -----------------------------------------------------------------
00305   Url::Url(const zypp::url::UrlRef &url)
00306     : m_impl( url)
00307   {
00308     if( !m_impl)
00309     {
00310       ZYPP_THROW(url::UrlException(
00311         _("Invalid empty Url object reference")
00312       ));
00313     }
00314   }
00315 
00316 
00317   // -----------------------------------------------------------------
00318   Url::Url(const std::string &encodedUrl)
00319     : m_impl( parseUrl(encodedUrl))
00320   {
00321     if( !m_impl)
00322     {
00323       ZYPP_THROW(url::UrlParsingException(
00324         _("Unable to parse Url components")
00325       ));
00326     }
00327   }
00328 
00329 
00330   // -----------------------------------------------------------------
00331   Url&
00332   Url::operator = (const std::string &encodedUrl)
00333   {
00334     UrlRef url( parseUrl(encodedUrl));
00335     if( !url)
00336     {
00337       ZYPP_THROW(url::UrlParsingException(
00338         _("Unable to parse Url components")
00339       ));
00340     }
00341     m_impl = url;
00342     return *this;
00343   }
00344 
00345 
00346   // -----------------------------------------------------------------
00347   Url&
00348   Url::operator = (const Url &url)
00349   {
00350     m_impl = url.m_impl;
00351     return *this;
00352   }
00353 
00354 
00355   // -----------------------------------------------------------------
00356   // static
00357   bool
00358   Url::registerScheme(const std::string &scheme,
00359                       UrlRef            urlImpl)
00360   {
00361     return g_urlSchemeRepository().addUrlByScheme(scheme, urlImpl);
00362   }
00363 
00364 
00365   // -----------------------------------------------------------------
00366   // static
00367   UrlRef
00368   Url::parseUrl(const std::string &encodedUrl)
00369   {
00370     UrlRef      url;
00371     str::smatch out;
00372     bool        ret = false;
00373 
00374     try
00375     {
00376       str::regex  rex(RX_SPLIT_URL);
00377       ret = str::regex_match(encodedUrl, out, rex);
00378     }
00379     catch( ... )
00380     {}
00381 
00382     if(ret && out.size() == 6)
00383     {
00384       std::string scheme = out[1];
00385       if (scheme.size() > 1)
00386         scheme = scheme.substr(0, scheme.size()-1);
00387       std::string authority = out[2];
00388       if (authority.size() >= 2)
00389         authority = authority.substr(2);
00390       std::string query = out[4];
00391       if (query.size() > 1)
00392         query = query.substr(1);
00393       std::string fragment = out[5];
00394       if (fragment.size() > 1)
00395         fragment = fragment.substr(1);
00396 
00397       url = g_urlSchemeRepository().getUrlByScheme(scheme);
00398       if( !url)
00399       {
00400         url.reset( new UrlBase());
00401       }
00402       url->init(scheme, authority, out[3],
00403                 query, fragment);
00404     }
00405     return url;
00406   }
00407 
00408 
00409   // -----------------------------------------------------------------
00410   // static
00411   zypp::url::UrlSchemes
00412   Url::getRegisteredSchemes()
00413   {
00414     return g_urlSchemeRepository().getRegisteredSchemes();
00415   }
00416 
00417 
00418   // -----------------------------------------------------------------
00419   // static
00420   bool
00421   Url::isRegisteredScheme(const std::string &scheme)
00422   {
00423     return g_urlSchemeRepository().isRegisteredScheme(scheme);
00424   }
00425 
00426 
00427   // -----------------------------------------------------------------
00428   zypp::url::UrlSchemes
00429   Url::getKnownSchemes() const
00430   {
00431     return m_impl->getKnownSchemes();
00432   }
00433 
00434 
00435   // -----------------------------------------------------------------
00436   bool
00437   Url::isValidScheme(const std::string &scheme) const
00438   {
00439     return m_impl->isValidScheme(scheme);
00440   }
00441 
00442 
00444   namespace
00445   {
00446     inline bool isInList( const char ** begin_r, const char ** end_r, const std::string & scheme_r )
00447     {
00448       for ( ; begin_r != end_r; ++begin_r )
00449         if ( scheme_r == *begin_r )
00450           return true;
00451       return false;
00452     }
00453   }
00454   bool Url::schemeIsLocal( const std::string & scheme_r )
00455   {
00456     static const char * val[] = { "cd", "dvd", "dir", "hd", "iso", "file" };
00457     return isInList( arrayBegin(val), arrayEnd(val), scheme_r );
00458   }
00459 
00460   bool Url::schemeIsRemote( const std::string & scheme_r )
00461   {
00462     static const char * val[] = { "http", "https", "nfs", "nfs4", "smb", "cifs", "ftp", "sftp" };
00463     return isInList( arrayBegin(val), arrayEnd(val), scheme_r );
00464   }
00465 
00466   bool Url::schemeIsVolatile( const std::string & scheme_r )
00467   {
00468     static const char * val[] = { "cd", "dvd" };
00469     return isInList( arrayBegin(val), arrayEnd(val), scheme_r );
00470   }
00471 
00472   bool Url::schemeIsDownloading( const std::string & scheme_r )
00473   {
00474     static const char * val[] = { "http", "https", "ftp", "sftp" };
00475     return isInList( arrayBegin(val), arrayEnd(val), scheme_r );
00476   }
00478 
00479   // -----------------------------------------------------------------
00480   bool
00481   Url::isValid() const
00482   {
00483     return m_impl->isValid();
00484   }
00485 
00486 
00487   // -----------------------------------------------------------------
00488   std::string
00489   Url::asString() const
00490   {
00491     return m_impl->asString();
00492   }
00493 
00494 
00495   // -----------------------------------------------------------------
00496   std::string
00497   Url::asCompleteString() const
00498   {
00499     // make sure, all url components are included;
00500     // regardless of the current configuration...
00501     ViewOptions opts(getViewOptions() +
00502                      ViewOption::WITH_SCHEME +
00503                      ViewOption::WITH_USERNAME +
00504                      ViewOption::WITH_PASSWORD +
00505                      ViewOption::WITH_HOST +
00506                      ViewOption::WITH_PORT +
00507                      ViewOption::WITH_PATH_NAME +
00508                      ViewOption::WITH_PATH_PARAMS +
00509                      ViewOption::WITH_QUERY_STR +
00510                      ViewOption::WITH_FRAGMENT);
00511     return m_impl->asString(opts);
00512   }
00513 
00514 
00515   // -----------------------------------------------------------------
00516   std::string
00517   Url::asString(const ViewOptions &opts) const
00518   {
00519     return m_impl->asString(opts);
00520   }
00521 
00522 
00523   // -----------------------------------------------------------------
00524   std::string
00525   Url::getScheme() const
00526   {
00527     return m_impl->getScheme();
00528   }
00529 
00530 
00531   // -----------------------------------------------------------------
00532   std::string
00533   Url::getAuthority() const
00534   {
00535     return m_impl->getAuthority();
00536   }
00537 
00538   // -----------------------------------------------------------------
00539   std::string
00540   Url::getPathData() const
00541   {
00542     return m_impl->getPathData();
00543   }
00544 
00545 
00546   // -----------------------------------------------------------------
00547   std::string
00548   Url::getQueryString() const
00549   {
00550     return m_impl->getQueryString();
00551   }
00552 
00553 
00554   // -----------------------------------------------------------------
00555   std::string
00556   Url::getFragment(zypp::url::EEncoding eflag) const
00557   {
00558     return m_impl->getFragment(eflag);
00559   }
00560 
00561 
00562   // -----------------------------------------------------------------
00563   std::string
00564   Url::getUsername(EEncoding eflag) const
00565   {
00566     return m_impl->getUsername(eflag);
00567   }
00568 
00569 
00570   // -----------------------------------------------------------------
00571   std::string
00572   Url::getPassword(EEncoding eflag) const
00573   {
00574     return m_impl->getPassword(eflag);
00575   }
00576 
00577 
00578   // -----------------------------------------------------------------
00579   std::string
00580   Url::getHost(EEncoding eflag) const
00581   {
00582     return m_impl->getHost(eflag);
00583   }
00584 
00585 
00586   // -----------------------------------------------------------------
00587   std::string
00588   Url::getPort() const
00589   {
00590     return m_impl->getPort();
00591   }
00592 
00593 
00594   // -----------------------------------------------------------------
00595   std::string
00596   Url::getPathName(EEncoding eflag) const
00597   {
00598     return m_impl->getPathName(eflag);
00599   }
00600 
00601 
00602   // -----------------------------------------------------------------
00603   std::string
00604   Url::getPathParams() const
00605   {
00606     return m_impl->getPathParams();
00607   }
00608 
00609 
00610   // -----------------------------------------------------------------
00611   zypp::url::ParamVec
00612   Url::getPathParamsVec() const
00613   {
00614     return m_impl->getPathParamsVec();
00615   }
00616 
00617 
00618   // -----------------------------------------------------------------
00619   zypp::url::ParamMap
00620   Url::getPathParamsMap(EEncoding eflag) const
00621   {
00622     return m_impl->getPathParamsMap(eflag);
00623   }
00624 
00625 
00626   // -----------------------------------------------------------------
00627   std::string
00628   Url::getPathParam(const std::string &param, EEncoding eflag) const
00629   {
00630     return m_impl->getPathParam(param, eflag);
00631   }
00632 
00633 
00634   // -----------------------------------------------------------------
00635   zypp::url::ParamVec
00636   Url::getQueryStringVec() const
00637   {
00638     return m_impl->getQueryStringVec();
00639   }
00640 
00641 
00642   // -----------------------------------------------------------------
00643   zypp::url::ParamMap
00644   Url::getQueryStringMap(EEncoding eflag) const
00645   {
00646     return m_impl->getQueryStringMap(eflag);
00647   }
00648 
00649 
00650   // -----------------------------------------------------------------
00651   std::string
00652   Url::getQueryParam(const std::string &param, EEncoding eflag) const
00653   {
00654     return m_impl->getQueryParam(param, eflag);
00655   }
00656 
00657 
00658   // -----------------------------------------------------------------
00659   void
00660   Url::setScheme(const std::string &scheme)
00661   {
00662     if(scheme == m_impl->getScheme())
00663     {
00664       return;
00665     }
00666     if( m_impl->isKnownScheme(scheme))
00667     {
00668       m_impl->setScheme(scheme);
00669       return;
00670     }
00671 
00672     UrlRef url = g_urlSchemeRepository().getUrlByScheme(scheme);
00673     if( !url)
00674     {
00675       url.reset( new UrlBase());
00676     }
00677     url->init(
00678       scheme,
00679       m_impl->getAuthority(),
00680       m_impl->getPathData(),
00681       m_impl->getQueryString(),
00682       m_impl->getFragment(zypp::url::E_ENCODED)
00683     );
00684     m_impl = url;
00685   }
00686 
00687 
00688   // -----------------------------------------------------------------
00689   void
00690   Url::setAuthority(const std::string &authority)
00691   {
00692     m_impl->setAuthority(authority);
00693   }
00694 
00695 
00696   // -----------------------------------------------------------------
00697   void
00698   Url::setPathData(const std::string &pathdata)
00699   {
00700     m_impl->setPathData(pathdata);
00701   }
00702 
00703 
00704   // -----------------------------------------------------------------
00705   void
00706   Url::setQueryString(const std::string &querystr)
00707   {
00708     m_impl->setQueryString(querystr);
00709   }
00710 
00711 
00712   // -----------------------------------------------------------------
00713   void
00714   Url::setFragment(const std::string &fragment, EEncoding eflag)
00715   {
00716     m_impl->setFragment(fragment, eflag);
00717   }
00718 
00719 
00720   // -----------------------------------------------------------------
00721   void
00722   Url::setUsername(const std::string &user,
00723                    EEncoding         eflag)
00724   {
00725     m_impl->setUsername(user, eflag);
00726   }
00727 
00728 
00729   // -----------------------------------------------------------------
00730   void
00731   Url::setPassword(const std::string &pass,
00732                    EEncoding         eflag)
00733   {
00734     m_impl->setPassword(pass, eflag);
00735   }
00736 
00737 
00738   // -----------------------------------------------------------------
00739   void
00740   Url::setHost(const std::string &host)
00741   {
00742     m_impl->setHost(host);
00743   }
00744 
00745 
00746   // -----------------------------------------------------------------
00747   void
00748   Url::setPort(const std::string &port)
00749   {
00750     m_impl->setPort(port);
00751   }
00752 
00753 
00754   // -----------------------------------------------------------------
00755   void
00756   Url::setPathName(const std::string &path,
00757                    EEncoding         eflag)
00758   {
00759     m_impl->setPathName(path, eflag);
00760   }
00761 
00762 
00763   // -----------------------------------------------------------------
00764   void
00765   Url::setPathParams(const std::string &params)
00766   {
00767     m_impl->setPathParams(params);
00768   }
00769 
00770 
00771   // -----------------------------------------------------------------
00772   void
00773   Url::setPathParamsVec(const zypp::url::ParamVec &pvec)
00774   {
00775     m_impl->setPathParamsVec(pvec);
00776   }
00777 
00778 
00779   // -----------------------------------------------------------------
00780   void
00781   Url::setPathParamsMap(const zypp::url::ParamMap &pmap)
00782   {
00783     m_impl->setPathParamsMap(pmap);
00784   }
00785 
00786 
00787   // -----------------------------------------------------------------
00788   void
00789   Url::setPathParam(const std::string &param, const std::string &value)
00790   {
00791     m_impl->setPathParam(param, value);
00792   }
00793 
00794 
00795   // -----------------------------------------------------------------
00796   void
00797   Url::setQueryStringVec(const zypp::url::ParamVec &pvec)
00798   {
00799     m_impl->setQueryStringVec(pvec);
00800   }
00801 
00802 
00803   // -----------------------------------------------------------------
00804   void
00805   Url::setQueryStringMap(const zypp::url::ParamMap &pmap)
00806   {
00807     m_impl->setQueryStringMap(pmap);
00808   }
00809 
00810   // -----------------------------------------------------------------
00811   void
00812   Url::setQueryParam(const std::string &param, const std::string &value)
00813   {
00814     m_impl->setQueryParam(param, value);
00815   }
00816 
00817   // -----------------------------------------------------------------
00818   void
00819   Url::delQueryParam(const std::string &param)
00820   {
00821     m_impl->delQueryParam(param);
00822   }
00823 
00824   // -----------------------------------------------------------------
00825   ViewOptions
00826   Url::getViewOptions() const
00827   {
00828     return m_impl->getViewOptions();
00829   }
00830 
00831   // -----------------------------------------------------------------
00832   void
00833   Url::setViewOptions(const ViewOptions &vopts)
00834   {
00835     m_impl->setViewOptions(vopts);
00836   }
00837 
00838   // -----------------------------------------------------------------
00839   std::ostream & operator<<( std::ostream & str, const Url & url )
00840   {
00841     return str << url.asString();
00842   }
00843 
00844   bool operator<( const Url &lhs, const Url &rhs )
00845   {
00846     return (lhs.asCompleteString() < rhs.asCompleteString());
00847   }
00848 
00849   bool operator==( const Url &lhs, const Url &rhs )
00850   {
00851     return (lhs.asCompleteString() == rhs.asCompleteString());
00852   }
00853 
00854   bool operator!=( const Url &lhs, const Url &rhs )
00855   {
00856     return (lhs.asCompleteString() != rhs.asCompleteString());
00857   }
00858 
00860 } // namespace zypp
00862 /*
00863 ** vim: set ts=2 sts=2 sw=2 ai et:
00864 */