00001
00002
00003
00004
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
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
00081
00082
00083 config("require_host", "y");
00084
00085
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
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
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");
00184 ref->config("require_pathname", "m");
00185 addUrlByScheme("hd", ref);
00186 addUrlByScheme("cd", ref);
00187 addUrlByScheme("dvd", ref);
00188 addUrlByScheme("dir", ref);
00189 addUrlByScheme("iso", ref);
00190
00191
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);
00197
00198
00199 ref->config("with_authority", "y");
00200 ref->config("with_port", "n");
00201 ref->config("rx_username", "");
00202 ref->config("rx_password", "");
00203 addUrlByScheme("file", ref);
00204
00205
00206 ref.reset( new UrlBase());
00207 ref->config("require_host", "m");
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");
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 }
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
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
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() == 5)
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
00411 zypp::url::UrlSchemes
00412 Url::getRegisteredSchemes()
00413 {
00414 return g_urlSchemeRepository().getRegisteredSchemes();
00415 }
00416
00417
00418
00419
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
00500
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 ¶m, 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 ¶m, 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 ¶ms)
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 ¶m, 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 ¶m, const std::string &value)
00813 {
00814 m_impl->setQueryParam(param, value);
00815 }
00816
00817
00818 ViewOptions
00819 Url::getViewOptions() const
00820 {
00821 return m_impl->getViewOptions();
00822 }
00823
00824
00825 void
00826 Url::setViewOptions(const ViewOptions &vopts)
00827 {
00828 m_impl->setViewOptions(vopts);
00829 }
00830
00831
00832 std::ostream & operator<<( std::ostream & str, const Url & url )
00833 {
00834 return str << url.asString();
00835 }
00836
00837 bool operator<( const Url &lhs, const Url &rhs )
00838 {
00839 return (lhs.asCompleteString() < rhs.asCompleteString());
00840 }
00841
00842 bool operator==( const Url &lhs, const Url &rhs )
00843 {
00844 return (lhs.asCompleteString() == rhs.asCompleteString());
00845 }
00846
00847 bool operator!=( const Url &lhs, const Url &rhs )
00848 {
00849 return (lhs.asCompleteString() != rhs.asCompleteString());
00850 }
00851
00853 }
00855
00856
00857