libzypp 9.41.1

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