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 
00197         // RFC1738, 3.10: may contain a host
00198         ref->config("with_authority",   "y");   // allow host,
00199         ref->config("with_port",        "n");   // but no port,
00200         ref->config("rx_username",      "");    // username or
00201         ref->config("rx_password",      "");    // password ...
00202         addUrlByScheme("file",   ref);
00203 
00204         // =====================================
00205         ref.reset( new UrlBase());
00206         ref->config("require_host",     "m");   // host is mandatory
00207         addUrlByScheme("nfs",    ref);
00208         addUrlByScheme("nfs4",   ref);
00209         addUrlByScheme("smb",    ref);
00210         addUrlByScheme("cifs",   ref);
00211         addUrlByScheme("http",   ref);
00212         addUrlByScheme("https",  ref);
00213         ref->config("path_encode_slash2", "y"); // always encode 2. slash
00214         addUrlByScheme("ftp",    ref);
00215         addUrlByScheme("sftp",   ref);
00216       }
00217 
00218       bool
00219       addUrlByScheme(const std::string &scheme,
00220                      UrlRef            urlImpl)
00221       {
00222         if( urlImpl && urlImpl->isValidScheme(scheme))
00223         {
00224           UrlRef ref(urlImpl);
00225           ref->clear();
00226           urlByScheme[str::toLower(scheme)] = ref;
00227           return true;
00228         }
00229         return false;
00230       }
00231 
00232       UrlRef
00233       getUrlByScheme(const std::string &scheme) const
00234       {
00235         UrlBySchemeMap::const_iterator i(urlByScheme.find(str::toLower(scheme)));
00236         if( i != urlByScheme.end())
00237         {
00238           return i->second;
00239         }
00240         return UrlRef();
00241       }
00242 
00243       bool
00244       isRegisteredScheme(const std::string &scheme) const
00245       {
00246         return urlByScheme.find(str::toLower(scheme)) != urlByScheme.end();
00247       }
00248 
00249       UrlSchemes
00250       getRegisteredSchemes() const
00251       {
00252         UrlBySchemeMap::const_iterator i(urlByScheme.begin());
00253         UrlSchemes                     schemes;
00254 
00255         schemes.reserve(urlByScheme.size());
00256         for( ; i != urlByScheme.end(); ++i)
00257         {
00258           schemes.push_back(i->first);
00259         }
00260         return schemes;
00261       }
00262     };
00263 
00264 
00265     // ---------------------------------------------------------------
00266     UrlByScheme & g_urlSchemeRepository()
00267     {
00268       static UrlByScheme _v;
00269       return _v;
00270     }
00271 
00273   } // anonymous namespace
00275 
00276 
00277   // -----------------------------------------------------------------
00278   Url::~Url()
00279   {
00280   }
00281 
00282 
00283   // -----------------------------------------------------------------
00284   Url::Url()
00285     : m_impl( new UrlBase())
00286   {
00287   }
00288 
00289 
00290   // -----------------------------------------------------------------
00291   Url::Url(const Url &url)
00292     : m_impl( url.m_impl)
00293   {
00294     if( !m_impl)
00295     {
00296       ZYPP_THROW(url::UrlException(
00297         _("Unable to clone Url object")
00298       ));
00299     }
00300   }
00301 
00302 
00303   // -----------------------------------------------------------------
00304   Url::Url(const zypp::url::UrlRef &url)
00305     : m_impl( url)
00306   {
00307     if( !m_impl)
00308     {
00309       ZYPP_THROW(url::UrlException(
00310         _("Invalid empty Url object reference")
00311       ));
00312     }
00313   }
00314 
00315 
00316   // -----------------------------------------------------------------
00317   Url::Url(const std::string &encodedUrl)
00318     : m_impl( parseUrl(encodedUrl))
00319   {
00320     if( !m_impl)
00321     {
00322       ZYPP_THROW(url::UrlParsingException(
00323         _("Unable to parse Url components")
00324       ));
00325     }
00326   }
00327 
00328 
00329   // -----------------------------------------------------------------
00330   Url&
00331   Url::operator = (const std::string &encodedUrl)
00332   {
00333     UrlRef url( parseUrl(encodedUrl));
00334     if( !url)
00335     {
00336       ZYPP_THROW(url::UrlParsingException(
00337         _("Unable to parse Url components")
00338       ));
00339     }
00340     m_impl = url;
00341     return *this;
00342   }
00343 
00344 
00345   // -----------------------------------------------------------------
00346   Url&
00347   Url::operator = (const Url &url)
00348   {
00349     m_impl = url.m_impl;
00350     return *this;
00351   }
00352 
00353 
00354   // -----------------------------------------------------------------
00355   // static
00356   bool
00357   Url::registerScheme(const std::string &scheme,
00358                       UrlRef            urlImpl)
00359   {
00360     return g_urlSchemeRepository().addUrlByScheme(scheme, urlImpl);
00361   }
00362 
00363 
00364   // -----------------------------------------------------------------
00365   // static
00366   UrlRef
00367   Url::parseUrl(const std::string &encodedUrl)
00368   {
00369     UrlRef      url;
00370     str::smatch out;
00371     bool        ret = false;
00372 
00373     try
00374     {
00375       str::regex  rex(RX_SPLIT_URL);
00376       ret = str::regex_match(encodedUrl, out, rex);
00377     }
00378     catch( ... )
00379     {}
00380 
00381     if(ret && out.size() == 5)
00382     {
00383       std::string scheme = out[1];
00384       if (scheme.size() > 1)
00385         scheme = scheme.substr(0, scheme.size()-1);
00386       std::string authority = out[2];
00387       if (authority.size() >= 2)
00388         authority = authority.substr(2);
00389       std::string query = out[4];
00390       if (query.size() > 1)
00391         query = query.substr(1);
00392       std::string fragment = out[5];
00393       if (fragment.size() > 1)
00394         fragment = fragment.substr(1);
00395 
00396       url = g_urlSchemeRepository().getUrlByScheme(scheme);
00397       if( !url)
00398       {
00399         url.reset( new UrlBase());
00400       }
00401       url->init(scheme, authority, out[3],
00402                 query, fragment);
00403     }
00404     return url;
00405   }
00406 
00407 
00408   // -----------------------------------------------------------------
00409   // static
00410   zypp::url::UrlSchemes
00411   Url::getRegisteredSchemes()
00412   {
00413     return g_urlSchemeRepository().getRegisteredSchemes();
00414   }
00415 
00416 
00417   // -----------------------------------------------------------------
00418   // static
00419   bool
00420   Url::isRegisteredScheme(const std::string &scheme)
00421   {
00422     return g_urlSchemeRepository().isRegisteredScheme(scheme);
00423   }
00424 
00425 
00426   // -----------------------------------------------------------------
00427   zypp::url::UrlSchemes
00428   Url::getKnownSchemes() const
00429   {
00430     return m_impl->getKnownSchemes();
00431   }
00432 
00433 
00434   // -----------------------------------------------------------------
00435   bool
00436   Url::isValidScheme(const std::string &scheme) const
00437   {
00438     return m_impl->isValidScheme(scheme);
00439   }
00440 
00441 
00443   namespace
00444   {
00445     inline bool isInList( const char ** begin_r, const char ** end_r, const std::string & scheme_r )
00446     {
00447       for ( ; begin_r != end_r; ++begin_r )
00448         if ( scheme_r == *begin_r )
00449           return true;
00450       return false;
00451     }
00452   }
00453   bool Url::schemeIsLocal( const std::string & scheme_r )
00454   {
00455     static const char * val[] = { "cd", "dvd", "dir", "hd", "iso", "file" };
00456     return isInList( arrayBegin(val), arrayEnd(val), scheme_r );
00457   }
00458 
00459   bool Url::schemeIsRemote( const std::string & scheme_r )
00460   {
00461     static const char * val[] = { "http", "https", "nfs", "nfs4", "smb", "cifs", "ftp", "sftp" };
00462     return isInList( arrayBegin(val), arrayEnd(val), scheme_r );
00463   }
00464 
00465   bool Url::schemeIsVolatile( const std::string & scheme_r )
00466   {
00467     static const char * val[] = { "cd", "dvd" };
00468     return isInList( arrayBegin(val), arrayEnd(val), scheme_r );
00469   }
00470 
00471   bool Url::schemeIsDownloading( const std::string & scheme_r )
00472   {
00473     static const char * val[] = { "http", "https", "ftp", "sftp" };
00474     return isInList( arrayBegin(val), arrayEnd(val), scheme_r );
00475   }
00477 
00478   // -----------------------------------------------------------------
00479   bool
00480   Url::isValid() const
00481   {
00482     return m_impl->isValid();
00483   }
00484 
00485 
00486   // -----------------------------------------------------------------
00487   std::string
00488   Url::asString() const
00489   {
00490     return m_impl->asString();
00491   }
00492 
00493 
00494   // -----------------------------------------------------------------
00495   std::string
00496   Url::asCompleteString() const
00497   {
00498     // make sure, all url components are included;
00499     // regardless of the current configuration...
00500     ViewOptions opts(getViewOptions() +
00501                      ViewOption::WITH_SCHEME +
00502                      ViewOption::WITH_USERNAME +
00503                      ViewOption::WITH_PASSWORD +
00504                      ViewOption::WITH_HOST +
00505                      ViewOption::WITH_PORT +
00506                      ViewOption::WITH_PATH_NAME +
00507                      ViewOption::WITH_PATH_PARAMS +
00508                      ViewOption::WITH_QUERY_STR +
00509                      ViewOption::WITH_FRAGMENT);
00510     return m_impl->asString(opts);
00511   }
00512 
00513 
00514   // -----------------------------------------------------------------
00515   std::string
00516   Url::asString(const ViewOptions &opts) const
00517   {
00518     return m_impl->asString(opts);
00519   }
00520 
00521 
00522   // -----------------------------------------------------------------
00523   std::string
00524   Url::getScheme() const
00525   {
00526     return m_impl->getScheme();
00527   }
00528 
00529 
00530   // -----------------------------------------------------------------
00531   std::string
00532   Url::getAuthority() const
00533   {
00534     return m_impl->getAuthority();
00535   }
00536 
00537   // -----------------------------------------------------------------
00538   std::string
00539   Url::getPathData() const
00540   {
00541     return m_impl->getPathData();
00542   }
00543 
00544 
00545   // -----------------------------------------------------------------
00546   std::string
00547   Url::getQueryString() const
00548   {
00549     return m_impl->getQueryString();
00550   }
00551 
00552 
00553   // -----------------------------------------------------------------
00554   std::string
00555   Url::getFragment(zypp::url::EEncoding eflag) const
00556   {
00557     return m_impl->getFragment(eflag);
00558   }
00559 
00560 
00561   // -----------------------------------------------------------------
00562   std::string
00563   Url::getUsername(EEncoding eflag) const
00564   {
00565     return m_impl->getUsername(eflag);
00566   }
00567 
00568 
00569   // -----------------------------------------------------------------
00570   std::string
00571   Url::getPassword(EEncoding eflag) const
00572   {
00573     return m_impl->getPassword(eflag);
00574   }
00575 
00576 
00577   // -----------------------------------------------------------------
00578   std::string
00579   Url::getHost(EEncoding eflag) const
00580   {
00581     return m_impl->getHost(eflag);
00582   }
00583 
00584 
00585   // -----------------------------------------------------------------
00586   std::string
00587   Url::getPort() const
00588   {
00589     return m_impl->getPort();
00590   }
00591 
00592 
00593   // -----------------------------------------------------------------
00594   std::string
00595   Url::getPathName(EEncoding eflag) const
00596   {
00597     return m_impl->getPathName(eflag);
00598   }
00599 
00600 
00601   // -----------------------------------------------------------------
00602   std::string
00603   Url::getPathParams() const
00604   {
00605     return m_impl->getPathParams();
00606   }
00607 
00608 
00609   // -----------------------------------------------------------------
00610   zypp::url::ParamVec
00611   Url::getPathParamsVec() const
00612   {
00613     return m_impl->getPathParamsVec();
00614   }
00615 
00616 
00617   // -----------------------------------------------------------------
00618   zypp::url::ParamMap
00619   Url::getPathParamsMap(EEncoding eflag) const
00620   {
00621     return m_impl->getPathParamsMap(eflag);
00622   }
00623 
00624 
00625   // -----------------------------------------------------------------
00626   std::string
00627   Url::getPathParam(const std::string &param, EEncoding eflag) const
00628   {
00629     return m_impl->getPathParam(param, eflag);
00630   }
00631 
00632 
00633   // -----------------------------------------------------------------
00634   zypp::url::ParamVec
00635   Url::getQueryStringVec() const
00636   {
00637     return m_impl->getQueryStringVec();
00638   }
00639 
00640 
00641   // -----------------------------------------------------------------
00642   zypp::url::ParamMap
00643   Url::getQueryStringMap(EEncoding eflag) const
00644   {
00645     return m_impl->getQueryStringMap(eflag);
00646   }
00647 
00648 
00649   // -----------------------------------------------------------------
00650   std::string
00651   Url::getQueryParam(const std::string &param, EEncoding eflag) const
00652   {
00653     return m_impl->getQueryParam(param, eflag);
00654   }
00655 
00656 
00657   // -----------------------------------------------------------------
00658   void
00659   Url::setScheme(const std::string &scheme)
00660   {
00661     if(scheme == m_impl->getScheme())
00662     {
00663       return;
00664     }
00665     if( m_impl->isKnownScheme(scheme))
00666     {
00667       m_impl->setScheme(scheme);
00668       return;
00669     }
00670 
00671     UrlRef url = g_urlSchemeRepository().getUrlByScheme(scheme);
00672     if( !url)
00673     {
00674       url.reset( new UrlBase());
00675     }
00676     url->init(
00677       scheme,
00678       m_impl->getAuthority(),
00679       m_impl->getPathData(),
00680       m_impl->getQueryString(),
00681       m_impl->getFragment(zypp::url::E_ENCODED)
00682     );
00683     m_impl = url;
00684   }
00685 
00686 
00687   // -----------------------------------------------------------------
00688   void
00689   Url::setAuthority(const std::string &authority)
00690   {
00691     m_impl->setAuthority(authority);
00692   }
00693 
00694 
00695   // -----------------------------------------------------------------
00696   void
00697   Url::setPathData(const std::string &pathdata)
00698   {
00699     m_impl->setPathData(pathdata);
00700   }
00701 
00702 
00703   // -----------------------------------------------------------------
00704   void
00705   Url::setQueryString(const std::string &querystr)
00706   {
00707     m_impl->setQueryString(querystr);
00708   }
00709 
00710 
00711   // -----------------------------------------------------------------
00712   void
00713   Url::setFragment(const std::string &fragment, EEncoding eflag)
00714   {
00715     m_impl->setFragment(fragment, eflag);
00716   }
00717 
00718 
00719   // -----------------------------------------------------------------
00720   void
00721   Url::setUsername(const std::string &user,
00722                    EEncoding         eflag)
00723   {
00724     m_impl->setUsername(user, eflag);
00725   }
00726 
00727 
00728   // -----------------------------------------------------------------
00729   void
00730   Url::setPassword(const std::string &pass,
00731                    EEncoding         eflag)
00732   {
00733     m_impl->setPassword(pass, eflag);
00734   }
00735 
00736 
00737   // -----------------------------------------------------------------
00738   void
00739   Url::setHost(const std::string &host)
00740   {
00741     m_impl->setHost(host);
00742   }
00743 
00744 
00745   // -----------------------------------------------------------------
00746   void
00747   Url::setPort(const std::string &port)
00748   {
00749     m_impl->setPort(port);
00750   }
00751 
00752 
00753   // -----------------------------------------------------------------
00754   void
00755   Url::setPathName(const std::string &path,
00756                    EEncoding         eflag)
00757   {
00758     m_impl->setPathName(path, eflag);
00759   }
00760 
00761 
00762   // -----------------------------------------------------------------
00763   void
00764   Url::setPathParams(const std::string &params)
00765   {
00766     m_impl->setPathParams(params);
00767   }
00768 
00769 
00770   // -----------------------------------------------------------------
00771   void
00772   Url::setPathParamsVec(const zypp::url::ParamVec &pvec)
00773   {
00774     m_impl->setPathParamsVec(pvec);
00775   }
00776 
00777 
00778   // -----------------------------------------------------------------
00779   void
00780   Url::setPathParamsMap(const zypp::url::ParamMap &pmap)
00781   {
00782     m_impl->setPathParamsMap(pmap);
00783   }
00784 
00785 
00786   // -----------------------------------------------------------------
00787   void
00788   Url::setPathParam(const std::string &param, const std::string &value)
00789   {
00790     m_impl->setPathParam(param, value);
00791   }
00792 
00793 
00794   // -----------------------------------------------------------------
00795   void
00796   Url::setQueryStringVec(const zypp::url::ParamVec &pvec)
00797   {
00798     m_impl->setQueryStringVec(pvec);
00799   }
00800 
00801 
00802   // -----------------------------------------------------------------
00803   void
00804   Url::setQueryStringMap(const zypp::url::ParamMap &pmap)
00805   {
00806     m_impl->setQueryStringMap(pmap);
00807   }
00808 
00809   // -----------------------------------------------------------------
00810   void
00811   Url::setQueryParam(const std::string &param, const std::string &value)
00812   {
00813     m_impl->setQueryParam(param, value);
00814   }
00815 
00816   // -----------------------------------------------------------------
00817   ViewOptions
00818   Url::getViewOptions() const
00819   {
00820     return m_impl->getViewOptions();
00821   }
00822 
00823   // -----------------------------------------------------------------
00824   void
00825   Url::setViewOptions(const ViewOptions &vopts)
00826   {
00827     m_impl->setViewOptions(vopts);
00828   }
00829 
00830   // -----------------------------------------------------------------
00831   std::ostream & operator<<( std::ostream & str, const Url & url )
00832   {
00833     return str << url.asString();
00834   }
00835 
00836   bool operator<( const Url &lhs, const Url &rhs )
00837   {
00838     return (lhs.asCompleteString() < rhs.asCompleteString());
00839   }
00840 
00841   bool operator==( const Url &lhs, const Url &rhs )
00842   {
00843     return (lhs.asCompleteString() == rhs.asCompleteString());
00844   }
00845 
00846   bool operator!=( const Url &lhs, const Url &rhs )
00847   {
00848     return (lhs.asCompleteString() != rhs.asCompleteString());
00849   }
00850 
00852 } // namespace zypp
00854 /*
00855 ** vim: set ts=2 sts=2 sw=2 ai et:
00856 */
Generated on Fri Mar 2 09:45:54 2012 for libzypp by  doxygen 1.6.3