Url.cc

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

Generated on Tue Sep 25 19:23:11 2007 for libzypp by  doxygen 1.5.3