00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <zypp/url/UrlBase.h>
00013 #include <zypp/base/String.h>
00014 #include <zypp/base/Gettext.h>
00015 #include <zypp/base/Regex.h>
00016
00017 #include <stdexcept>
00018 #include <climits>
00019 #include <errno.h>
00020 #include <sys/types.h>
00021 #include <sys/socket.h>
00022 #include <arpa/inet.h>
00023
00024 #include <iostream>
00025
00026
00027
00028 #define a_zA_Z "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
00029
00030
00031
00032
00033
00034
00035
00036 #define RX_VALID_SCHEME "^[" a_zA_Z "][" a_zA_Z "0-9\\.+-]*$"
00037
00038 #define RX_VALID_PORT "^[0-9]{1,5}$"
00039
00040 #define RX_VALID_HOSTNAME "^[[:alnum:]]+([\\.-][[:alnum:]]+)*$"
00041
00042 #define RX_VALID_HOSTIPV4 \
00043 "^([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})$"
00044
00045 #define RX_VALID_HOSTIPV6 \
00046 "^\\[[:a-fA-F0-9]+(:[0-9]{1,3}(\\.[0-9]{1,3}){3})?\\]$"
00047
00048
00050 namespace zypp
00051 {
00052
00054 namespace url
00055 {
00056
00057
00058
00059
00060
00061
00062 const ViewOption ViewOption::WITH_SCHEME = 0x0001;
00063 const ViewOption ViewOption::WITH_USERNAME = 0x0002;
00064 const ViewOption ViewOption::WITH_PASSWORD = 0x0004;
00065 const ViewOption ViewOption::WITH_HOST = 0x0008;
00066 const ViewOption ViewOption::WITH_PORT = 0x0010;
00067 const ViewOption ViewOption::WITH_PATH_NAME = 0x0020;
00068 const ViewOption ViewOption::WITH_PATH_PARAMS = 0x0040;
00069 const ViewOption ViewOption::WITH_QUERY_STR = 0x0080;
00070 const ViewOption ViewOption::WITH_FRAGMENT = 0x0100;
00071 const ViewOption ViewOption::EMPTY_AUTHORITY = 0x0200;
00072 const ViewOption ViewOption::EMPTY_PATH_NAME = 0x0400;
00073 const ViewOption ViewOption::EMPTY_PATH_PARAMS = 0x0800;
00074 const ViewOption ViewOption::EMPTY_QUERY_STR = 0x1000;
00075 const ViewOption ViewOption::EMPTY_FRAGMENT = 0x2000;
00076 const ViewOption ViewOption::DEFAULTS = 0x07bb;
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 ViewOption::ViewOption()
00092 : opt(0x07bb)
00093 {}
00094
00095
00096 ViewOption::ViewOption(int option)
00097 : opt(option)
00098 {}
00099
00100
00101
00102
00103
00104
00105 typedef std::map< std::string, std::string > UrlConfig;
00106
00107
00108
00112 class UrlBaseData
00113 {
00114 public:
00115 UrlBaseData()
00116 {}
00117
00118 UrlBaseData(const UrlConfig &conf)
00119 : config(conf)
00120 {}
00121
00122 UrlConfig config;
00123 ViewOptions vopts;
00124
00125 std::string scheme;
00126 std::string user;
00127 std::string pass;
00128 std::string host;
00129 std::string port;
00130 std::string pathname;
00131 std::string pathparams;
00132 std::string querystr;
00133 std::string fragment;
00134 };
00135
00136
00137
00138
00139
00140
00141 namespace
00142 {
00143
00144
00145 inline void
00146 checkUrlData(const std::string &data,
00147 const std::string &name,
00148 const std::string ®x,
00149 bool show=true)
00150 {
00151 if( regx.empty() || regx == "^$")
00152 {
00153 ZYPP_THROW(UrlNotAllowedException(
00154 str::form(_("Url scheme does not allow a %s"), name.c_str())
00155 ));
00156 }
00157 else
00158 {
00159 bool valid = false;
00160 try
00161 {
00162 str::regex rex(regx);
00163 valid = str::regex_match(data, rex);
00164 }
00165 catch( ... )
00166 {}
00167
00168 if( !valid)
00169 {
00170 if( show)
00171 {
00172 ZYPP_THROW(UrlBadComponentException(
00173 str::form(_("Invalid %s component '%s'"),
00174 name.c_str(), data.c_str())
00175 ));
00176 }
00177 else
00178 {
00179 ZYPP_THROW(UrlBadComponentException(
00180 str::form(_("Invalid %s component"), name.c_str())
00181 ));
00182 }
00183 }
00184 }
00185 }
00186
00187 }
00188
00189
00190
00191 UrlBase::~UrlBase()
00192 {
00193 delete m_data;
00194 m_data = NULL;
00195 }
00196
00197
00198
00199 UrlBase::UrlBase()
00200 : m_data( new UrlBaseData())
00201 {
00202 configure();
00203 }
00204
00205
00206
00207 UrlBase::UrlBase(const UrlBase &url)
00208 : m_data( new UrlBaseData( *(url.m_data)))
00209 {
00210 }
00211
00212
00213
00214 UrlBase::UrlBase(const std::string &scheme,
00215 const std::string &authority,
00216 const std::string &pathdata,
00217 const std::string &querystr,
00218 const std::string &fragment)
00219 : m_data( new UrlBaseData())
00220 {
00221 configure();
00222 init(scheme, authority, pathdata, querystr, fragment);
00223 }
00224
00225
00226
00227 void
00228 UrlBase::init(const std::string &scheme,
00229 const std::string &authority,
00230 const std::string &pathdata,
00231 const std::string &querystr,
00232 const std::string &fragment)
00233 {
00234 setScheme(scheme);
00235 setAuthority(authority);
00236 setPathData(pathdata);
00237 setQueryString(querystr);
00238 setFragment(fragment, zypp::url::E_ENCODED);
00239 }
00240
00241
00242
00243 void
00244 UrlBase::configure()
00245 {
00246 config("sep_pathparams", ";");
00247 config("psep_pathparam", ",");
00248 config("vsep_pathparam", "=");
00249
00250 config("psep_querystr", "&");
00251 config("vsep_querystr", "=");
00252
00253 config("safe_username", "~!$&'()*+=,;");
00254 config("safe_password", "~!$&'()*+=,:;");
00255 config("safe_hostname", "[:]");
00256 config("safe_pathname", "~!$&'()*+=,:@/");
00257 config("safe_pathparams", "~!$&'()*+=,:;@/");
00258 config("safe_querystr", "~!$&'()*+=,:;@/?");
00259 config("safe_fragment", "~!$&'()*+=,:;@/?");
00260
00261
00262
00263 config("with_authority", "y");
00264 config("with_port", "y");
00265
00266
00267
00268
00269 config("require_host", "n");
00270 config("require_pathname","n");
00271
00272
00273
00274 config("path_encode_slash2", "n");
00275
00276 config("rx_username", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,;~\\._-]|%[a-fA-F0-9]{2})+$");
00277 config("rx_password", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,:;~\\._-]|%[a-fA-F0-9]{2})+$");
00278
00279 config("rx_pathname", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,:@/~\\._-]|%[a-fA-F0-9]{2})+$");
00280 config("rx_pathparams", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,:;@/~\\._-]|%[a-fA-F0-9]{2})+$");
00281
00282 config("rx_querystr", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
00283 config("rx_fragment", "^([" a_zA_Z "0-9!$&'\\(\\)*+=,:;@/?~\\._-]|%[a-fA-F0-9]{2})+$");
00284 }
00285
00286
00287
00288 void
00289 UrlBase::config(const std::string &opt, const std::string &val)
00290 {
00291 m_data->config[opt] = val;
00292 }
00293
00294
00295
00296 std::string
00297 UrlBase::config(const std::string &opt) const
00298 {
00299 UrlConfig::const_iterator v( m_data->config.find(opt));
00300 if( v != m_data->config.end())
00301 return v->second;
00302 else
00303 return std::string();
00304 }
00305
00306
00307
00308 ViewOptions
00309 UrlBase::getViewOptions() const
00310 {
00311 return m_data->vopts;
00312 }
00313
00314
00315
00316 void
00317 UrlBase::setViewOptions(const ViewOptions &vopts)
00318 {
00319 m_data->vopts = vopts;
00320 }
00321
00322
00323
00324 void
00325 UrlBase::clear()
00326 {
00327 zypp::url::UrlConfig config(m_data->config);
00328 zypp::url::ViewOptions vopts(m_data->vopts);
00329 *m_data = UrlBaseData();
00330 m_data->config = config;
00331 m_data->vopts = vopts;
00332 }
00333
00334
00335
00336 UrlBase *
00337 UrlBase::clone() const
00338 {
00339 return new UrlBase(*this);
00340 }
00341
00342
00343
00344 zypp::url::UrlSchemes
00345 UrlBase::getKnownSchemes() const
00346 {
00347 return UrlSchemes();
00348 }
00349
00350
00351
00352 bool
00353 UrlBase::isKnownScheme(const std::string &scheme) const
00354 {
00355 std::string lscheme( str::toLower(scheme));
00356 UrlSchemes schemes( getKnownSchemes());
00357 UrlSchemes::const_iterator s;
00358
00359 for(s=schemes.begin(); s!=schemes.end(); ++s)
00360 {
00361 if( lscheme == str::toLower(*s))
00362 return true;
00363 }
00364 return false;
00365 }
00366
00367
00368
00369 bool
00370 UrlBase::isValidScheme(const std::string &scheme) const
00371 {
00372 bool valid = false;
00373 try
00374 {
00375 str::regex rex(RX_VALID_SCHEME);
00376 valid = str::regex_match(scheme, rex);
00377 }
00378 catch( ... )
00379 {}
00380
00381 if(valid)
00382 {
00383 std::string lscheme( str::toLower(scheme));
00384 UrlSchemes schemes( getKnownSchemes());
00385
00386 if( schemes.empty())
00387 return true;
00388
00389 UrlSchemes::const_iterator s;
00390 for(s=schemes.begin(); s!=schemes.end(); ++s)
00391 {
00392 if( lscheme == str::toLower(*s))
00393 return true;
00394 }
00395 }
00396 return false;
00397 }
00398
00399
00400
00401 bool
00402 UrlBase::isValid() const
00403 {
00404
00405
00406
00407
00408
00409
00410 if( getScheme().empty())
00411 return false;
00412
00413 std::string host( getHost(zypp::url::E_ENCODED));
00414 if( host.empty() && config("require_host") != "n")
00415 return false;
00416
00417 std::string path( getPathName(zypp::url::E_ENCODED));
00418 if( path.empty() && config("require_pathname") != "n")
00419 return false;
00420
00421
00422
00423
00424
00425 if( !host.empty() && !path.empty() && path.at(0) != '/')
00426 return false;
00427
00428 return true;
00429 }
00430
00431
00432
00433 std::string
00434 UrlBase::asString() const
00435 {
00436 return asString(getViewOptions());
00437 }
00438
00439
00440
00441 std::string
00442 UrlBase::asString(const zypp::url::ViewOptions &opts) const
00443 {
00444 std::string url;
00445 UrlBaseData tmp;
00446
00447 if( opts.has(ViewOptions::WITH_SCHEME))
00448 {
00449 tmp.scheme = getScheme();
00450 if( !tmp.scheme.empty())
00451 {
00452 url += tmp.scheme + ":";
00453
00454 if( opts.has(ViewOptions::WITH_HOST))
00455 {
00456 tmp.host = getHost(zypp::url::E_ENCODED);
00457 if( !tmp.host.empty())
00458 {
00459 url += "//";
00460
00461 if( opts.has(ViewOptions::WITH_USERNAME))
00462 {
00463 tmp.user = getUsername(zypp::url::E_ENCODED);
00464 if( !tmp.user.empty())
00465 {
00466 url += tmp.user;
00467
00468 if( opts.has(ViewOptions::WITH_PASSWORD))
00469 {
00470 tmp.pass = getPassword(zypp::url::E_ENCODED);
00471 if( !tmp.pass.empty())
00472 {
00473 url += ":" + tmp.pass;
00474 }
00475 }
00476 url += "@";
00477 }
00478 }
00479
00480 url += tmp.host;
00481
00482 if( opts.has(ViewOptions::WITH_PORT))
00483 {
00484 tmp.port = getPort();
00485 if( !tmp.port.empty())
00486 {
00487 url += ":" + tmp.port;
00488 }
00489 }
00490 }
00491 else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
00492 {
00493 url += "//";
00494 }
00495 }
00496 else if( opts.has(ViewOptions::EMPTY_AUTHORITY))
00497 {
00498 url += "//";
00499 }
00500 }
00501 }
00502
00503 if( opts.has(ViewOptions::WITH_PATH_NAME))
00504 {
00505 tmp.pathname = getPathName(zypp::url::E_ENCODED);
00506 if( !tmp.pathname.empty())
00507 {
00508 if(url.find("/") != std::string::npos)
00509 {
00510
00511
00512 tmp.pathname = cleanupPathName(tmp.pathname, true);
00513 if(tmp.pathname.at(0) != '/')
00514 {
00515 url += "/";
00516 }
00517 }
00518 url += tmp.pathname;
00519
00520 if( opts.has(ViewOptions::WITH_PATH_PARAMS))
00521 {
00522 tmp.pathparams = getPathParams();
00523 if( !tmp.pathparams.empty())
00524 {
00525 url += ";" + tmp.pathparams;
00526 }
00527 else if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
00528 {
00529 url += ";";
00530 }
00531 }
00532 }
00533 else if( opts.has(ViewOptions::EMPTY_PATH_NAME)
00534 && url.find("/") != std::string::npos)
00535 {
00536 url += "/";
00537 if( opts.has(ViewOptions::EMPTY_PATH_PARAMS))
00538 {
00539 url += ";";
00540 }
00541 }
00542 }
00543
00544 if( opts.has(ViewOptions::WITH_QUERY_STR))
00545 {
00546 tmp.querystr = getQueryString();
00547 if( !tmp.querystr.empty())
00548 {
00549 url += "?" + tmp.querystr;
00550 }
00551 else if( opts.has(ViewOptions::EMPTY_QUERY_STR))
00552 {
00553 url += "?";
00554 }
00555 }
00556
00557 if( opts.has(ViewOptions::WITH_FRAGMENT))
00558 {
00559 tmp.fragment = getFragment(zypp::url::E_ENCODED);
00560 if( !tmp.fragment.empty())
00561 {
00562 url += "#" + tmp.fragment;
00563 }
00564 else if( opts.has(ViewOptions::EMPTY_FRAGMENT))
00565 {
00566 url += "#";
00567 }
00568 }
00569
00570 return url;
00571 }
00572
00573
00574
00575 std::string
00576 UrlBase::getScheme() const
00577 {
00578 return m_data->scheme;
00579 }
00580
00581
00582
00583 std::string
00584 UrlBase::getAuthority() const
00585 {
00586 std::string str;
00587 if( !getHost(zypp::url::E_ENCODED).empty())
00588 {
00589 if( !getUsername(zypp::url::E_ENCODED).empty())
00590 {
00591 str = getUsername(zypp::url::E_ENCODED);
00592 if( !getPassword(zypp::url::E_ENCODED).empty())
00593 {
00594 str += ":" + getPassword(zypp::url::E_ENCODED);
00595 }
00596 str += "@";
00597 }
00598
00599 str += getHost(zypp::url::E_ENCODED);
00600 if( !getPort().empty())
00601 {
00602 str += ":" + getPort();
00603 }
00604 }
00605 return str;
00606 }
00607
00608
00609
00610 std::string
00611 UrlBase::getPathData() const
00612 {
00613 return getPathName(zypp::url::E_ENCODED) +
00614 config("sep_pathparams") +
00615 getPathParams();
00616 }
00617
00618
00619
00620 std::string
00621 UrlBase::getQueryString() const
00622 {
00623 return m_data->querystr;
00624 }
00625
00626
00627
00628 std::string
00629 UrlBase::getFragment(EEncoding eflag) const
00630 {
00631 if(eflag == zypp::url::E_DECODED)
00632 return zypp::url::decode(m_data->fragment);
00633 else
00634 return m_data->fragment;
00635 }
00636
00637
00638
00639 std::string
00640 UrlBase::getUsername(EEncoding eflag) const
00641 {
00642 if(eflag == zypp::url::E_DECODED)
00643 return zypp::url::decode(m_data->user);
00644 else
00645 return m_data->user;
00646 }
00647
00648
00649
00650 std::string
00651 UrlBase::getPassword(EEncoding eflag) const
00652 {
00653 if(eflag == zypp::url::E_DECODED)
00654 return zypp::url::decode(m_data->pass);
00655 else
00656 return m_data->pass;
00657 }
00658
00659
00660
00661 std::string
00662 UrlBase::getHost(EEncoding eflag) const
00663 {
00664 if(eflag == zypp::url::E_DECODED)
00665 return zypp::url::decode(m_data->host);
00666 else
00667 return m_data->host;
00668 }
00669
00670
00671
00672 std::string
00673 UrlBase::getPort() const
00674 {
00675 return m_data->port;
00676 }
00677
00678
00679
00680 std::string
00681 UrlBase::getPathName(EEncoding eflag) const
00682 {
00683 if(eflag == zypp::url::E_DECODED)
00684 return zypp::url::decode(m_data->pathname);
00685 else
00686 return cleanupPathName(m_data->pathname);
00687 }
00688
00689
00690
00691 std::string
00692 UrlBase::getPathParams() const
00693 {
00694 return m_data->pathparams;
00695 }
00696
00697
00698
00699 zypp::url::ParamVec
00700 UrlBase::getPathParamsVec() const
00701 {
00702 zypp::url::ParamVec pvec;
00703 if( config("psep_pathparam").empty())
00704 {
00705 pvec.push_back(getPathParams());
00706 }
00707 else
00708 {
00709 zypp::url::split(
00710 pvec,
00711 getPathParams(),
00712 config("psep_pathparam")
00713 );
00714 }
00715 return pvec;
00716 }
00717
00718
00719
00720 zypp::url::ParamMap
00721 UrlBase::getPathParamsMap(EEncoding eflag) const
00722 {
00723 if( config("psep_pathparam").empty() ||
00724 config("vsep_pathparam").empty())
00725 {
00726 ZYPP_THROW(UrlNotSupportedException(
00727 _("Path parameter parsing not supported for this URL")
00728 ));
00729 }
00730 zypp::url::ParamMap pmap;
00731 zypp::url::split(
00732 pmap,
00733 getPathParams(),
00734 config("psep_pathparam"),
00735 config("vsep_pathparam"),
00736 eflag
00737 );
00738 return pmap;
00739 }
00740
00741
00742
00743 std::string
00744 UrlBase::getPathParam(const std::string ¶m, EEncoding eflag) const
00745 {
00746 zypp::url::ParamMap pmap( getPathParamsMap( eflag));
00747 zypp::url::ParamMap::const_iterator i( pmap.find(param));
00748
00749 return i != pmap.end() ? i->second : std::string();
00750 }
00751
00752
00753
00754 zypp::url::ParamVec
00755 UrlBase::getQueryStringVec() const
00756 {
00757 zypp::url::ParamVec pvec;
00758 if( config("psep_querystr").empty())
00759 {
00760 pvec.push_back(getQueryString());
00761 }
00762 else
00763 {
00764 zypp::url::split(
00765 pvec,
00766 getQueryString(),
00767 config("psep_querystr")
00768 );
00769 }
00770 return pvec;
00771 }
00772
00773
00774
00775 zypp::url::ParamMap
00776 UrlBase::getQueryStringMap(EEncoding eflag) const
00777 {
00778 if( config("psep_querystr").empty() ||
00779 config("vsep_querystr").empty())
00780 {
00781 ZYPP_THROW(UrlNotSupportedException(
00782 _("Query string parsing not supported for this URL")
00783 ));
00784 }
00785 zypp::url::ParamMap pmap;
00786 zypp::url::split(
00787 pmap,
00788 getQueryString(),
00789 config("psep_querystr"),
00790 config("vsep_querystr"),
00791 eflag
00792 );
00793 return pmap;
00794 }
00795
00796
00797
00798 std::string
00799 UrlBase::getQueryParam(const std::string ¶m, EEncoding eflag) const
00800 {
00801 zypp::url::ParamMap pmap( getQueryStringMap( eflag));
00802 zypp::url::ParamMap::const_iterator i( pmap.find(param));
00803
00804 return i != pmap.end() ? i->second : std::string();
00805 }
00806
00807
00808
00809 void
00810 UrlBase::setScheme(const std::string &scheme)
00811 {
00812 if( isValidScheme(scheme))
00813 {
00814 m_data->scheme = str::toLower(scheme);
00815 }
00816 else
00817 if( scheme.empty())
00818 {
00819 ZYPP_THROW(UrlBadComponentException(
00820 _("Url scheme is a required component")
00821 ));
00822 }
00823 else
00824 {
00825 ZYPP_THROW(UrlBadComponentException(
00826 str::form(_("Invalid Url scheme '%s'"), scheme.c_str())
00827 ));
00828 }
00829 }
00830
00831
00832
00833 void
00834 UrlBase::setAuthority(const std::string &authority)
00835 {
00836 std::string s = authority;
00837 std::string::size_type p,q;
00838
00839 std::string username, password, host, port;
00840
00841 if ((p=s.find('@')) != std::string::npos)
00842 {
00843 q = s.find(':');
00844 if (q != std::string::npos && q < p)
00845 {
00846 setUsername(s.substr(0, q), zypp::url::E_ENCODED);
00847 setPassword(s.substr(q+1, p-q-1), zypp::url::E_ENCODED);
00848 }
00849 else
00850 setUsername(s.substr(0, p), zypp::url::E_ENCODED);
00851 s = s.substr(p+1);
00852 }
00853 q = s.rfind(']');
00854 if ((p = s.rfind(':')) != std::string::npos && p > q+1)
00855 {
00856
00857 setHost(s.substr(0, p));
00858 setPort(s.substr(p+1));
00859 }
00860 else
00861 setHost(s);
00862 }
00863
00864
00865 void
00866 UrlBase::setPathData(const std::string &pathdata)
00867 {
00868 size_t pos = std::string::npos;
00869 std::string sep(config("sep_pathparams"));
00870
00871 if( !sep.empty())
00872 pos = pathdata.find(sep);
00873
00874 if( pos != std::string::npos)
00875 {
00876 setPathName(pathdata.substr(0, pos),
00877 zypp::url::E_ENCODED);
00878 setPathParams(pathdata.substr(pos + 1));
00879 }
00880 else
00881 {
00882 setPathName(pathdata,
00883 zypp::url::E_ENCODED);
00884 setPathParams("");
00885 }
00886 }
00887
00888
00889
00890 void
00891 UrlBase::setQueryString(const std::string &querystr)
00892 {
00893 if( querystr.empty())
00894 {
00895 m_data->querystr = querystr;
00896 }
00897 else
00898 {
00899 checkUrlData(querystr, "query string", config("rx_querystr"));
00900
00901 m_data->querystr = querystr;
00902 }
00903 }
00904
00905
00906
00907 void
00908 UrlBase::setFragment(const std::string &fragment,
00909 EEncoding eflag)
00910 {
00911 if( fragment.empty())
00912 {
00913 m_data->fragment = fragment;
00914 }
00915 else
00916 {
00917 if(eflag == zypp::url::E_ENCODED)
00918 {
00919 checkUrlData(fragment, "fragment", config("rx_fragment"));
00920
00921 m_data->fragment = fragment;
00922 }
00923 else
00924 {
00925 m_data->fragment = zypp::url::encode(
00926 fragment, config("safe_fragment")
00927 );
00928 }
00929 }
00930 }
00931
00932
00933
00934 void
00935 UrlBase::setUsername(const std::string &user,
00936 EEncoding eflag)
00937 {
00938 if( user.empty())
00939 {
00940 m_data->user = user;
00941 }
00942 else
00943 {
00944 if( config("with_authority") != "y")
00945 {
00946 ZYPP_THROW(UrlNotAllowedException(
00947 _("Url scheme does not allow a username")
00948 ));
00949 }
00950
00951 if(eflag == zypp::url::E_ENCODED)
00952 {
00953 checkUrlData(user, "username", config("rx_username"));
00954
00955 m_data->user = user;
00956 }
00957 else
00958 {
00959 m_data->user = zypp::url::encode(
00960 user, config("safe_username")
00961 );
00962 }
00963 }
00964 }
00965
00966
00967
00968 void
00969 UrlBase::setPassword(const std::string &pass,
00970 EEncoding eflag)
00971 {
00972 if( pass.empty())
00973 {
00974 m_data->pass = pass;
00975 }
00976 else
00977 {
00978 if( config("with_authority") != "y")
00979 {
00980 ZYPP_THROW(UrlNotAllowedException(
00981 _("Url scheme does not allow a password")
00982 ));
00983 }
00984
00985 if(eflag == zypp::url::E_ENCODED)
00986 {
00987 checkUrlData(pass, "password", config("rx_password"), false);
00988
00989 m_data->pass = pass;
00990 }
00991 else
00992 {
00993 m_data->pass = zypp::url::encode(
00994 pass, config("safe_password")
00995 );
00996 }
00997 }
00998 }
00999
01000
01001
01002 void
01003 UrlBase::setHost(const std::string &host)
01004 {
01005 if( host.empty())
01006 {
01007 if(config("require_host") == "m")
01008 {
01009 ZYPP_THROW(UrlNotAllowedException(
01010 _("Url scheme requires a host component")
01011 ));
01012 }
01013 m_data->host = host;
01014 }
01015 else
01016 {
01017 if( config("with_authority") != "y")
01018 {
01019 ZYPP_THROW(UrlNotAllowedException(
01020 _("Url scheme does not allow a host component")
01021 ));
01022 }
01023
01024 if( isValidHost(host))
01025 {
01026 std::string temp;
01027
01028
01029
01030
01031 if( host.at(0) == '[')
01032 {
01033 temp = str::toUpper(zypp::url::decode(host));
01034 }
01035 else
01036 {
01037 temp = str::toLower(zypp::url::decode(host));
01038 }
01039
01040 m_data->host = zypp::url::encode(
01041 temp, config("safe_hostname")
01042 );
01043 }
01044 else
01045 {
01046 ZYPP_THROW(UrlBadComponentException(
01047 str::form(_("Invalid host component '%s'"), host.c_str())
01048 ));
01049 }
01050 }
01051 }
01052
01053
01054
01055 void
01056 UrlBase::setPort(const std::string &port)
01057 {
01058 if( port.empty())
01059 {
01060 m_data->port = port;
01061 }
01062 else
01063 {
01064 if( config("with_authority") != "y" ||
01065 config("with_port") != "y")
01066 {
01067 ZYPP_THROW(UrlNotAllowedException(
01068 _("Url scheme does not allow a port")
01069 ));
01070 }
01071
01072 if( isValidPort(port))
01073 {
01074 m_data->port = port;
01075 }
01076 else
01077 {
01078 ZYPP_THROW(UrlBadComponentException(
01079 str::form(_("Invalid port component '%s'"), port.c_str())
01080 ));
01081 }
01082 }
01083 }
01084
01085
01086
01087 void
01088 UrlBase::setPathName(const std::string &path,
01089 EEncoding eflag)
01090 {
01091 if( path.empty())
01092 {
01093 if(config("require_pathname") == "m")
01094 {
01095 ZYPP_THROW(UrlNotAllowedException(
01096 _("Url scheme requires path name")
01097 ));
01098 }
01099 m_data->pathname = path;
01100 }
01101 else
01102 {
01103 if(eflag == zypp::url::E_ENCODED)
01104 {
01105 checkUrlData(path, "path name", config("rx_pathname"));
01106
01107 if( !getHost(zypp::url::E_ENCODED).empty())
01108 {
01109
01110
01111
01112
01113 if(!(path.at(0) == '/' || (path.size() >= 3 &&
01114 str::toLower(path.substr(0, 3)) == "%2f")))
01115 {
01116 ZYPP_THROW(UrlNotAllowedException(
01117 _("Relative path not allowed if authority exists")
01118 ));
01119 }
01120 }
01121
01122 m_data->pathname = cleanupPathName(path);
01123 }
01124 else
01125 {
01126 if( !getHost(zypp::url::E_ENCODED).empty())
01127 {
01128 if(path.at(0) != '/')
01129 {
01130 ZYPP_THROW(UrlNotAllowedException(
01131 _("Relative path not allowed if authority exists")
01132 ));
01133 }
01134 }
01135
01136 m_data->pathname = cleanupPathName(
01137 zypp::url::encode(
01138 path, config("safe_pathname")
01139 )
01140 );
01141 }
01142 }
01143 }
01144
01145
01146
01147 void
01148 UrlBase::setPathParams(const std::string ¶ms)
01149 {
01150 if( params.empty())
01151 {
01152 m_data->pathparams = params;
01153 }
01154 else
01155 {
01156 checkUrlData(params, "path parameters", config("rx_pathparams"));
01157
01158 m_data->pathparams = params;
01159 }
01160 }
01161
01162
01163
01164 void
01165 UrlBase::setPathParamsVec(const zypp::url::ParamVec &pvec)
01166 {
01167 setPathParams(
01168 zypp::url::join(
01169 pvec,
01170 config("psep_pathparam")
01171 )
01172 );
01173 }
01174
01175
01176
01177 void
01178 UrlBase::setPathParamsMap(const zypp::url::ParamMap &pmap)
01179 {
01180 if( config("psep_pathparam").empty() ||
01181 config("vsep_pathparam").empty())
01182 {
01183 ZYPP_THROW(UrlNotSupportedException(
01184 _("Path Parameter parsing not supported for this URL")
01185 ));
01186 }
01187 setPathParams(
01188 zypp::url::join(
01189 pmap,
01190 config("psep_pathparam"),
01191 config("vsep_pathparam"),
01192 config("safe_pathparams")
01193 )
01194 );
01195 }
01196
01197
01198
01199 void
01200 UrlBase::setPathParam(const std::string ¶m, const std::string &value)
01201 {
01202 zypp::url::ParamMap pmap( getPathParamsMap(zypp::url::E_DECODED));
01203 pmap[param] = value;
01204 setPathParamsMap(pmap);
01205 }
01206
01207
01208
01209 void
01210 UrlBase::setQueryStringVec(const zypp::url::ParamVec &pvec)
01211 {
01212 setQueryString(
01213 zypp::url::join(
01214 pvec,
01215 config("psep_querystr")
01216 )
01217 );
01218 }
01219
01220
01221
01222 void
01223 UrlBase::setQueryStringMap(const zypp::url::ParamMap &pmap)
01224 {
01225 if( config("psep_querystr").empty() ||
01226 config("vsep_querystr").empty())
01227 {
01228 ZYPP_THROW(UrlNotSupportedException(
01229 _("Query string parsing not supported for this URL")
01230 ));
01231 }
01232 setQueryString(
01233 zypp::url::join(
01234 pmap,
01235 config("psep_querystr"),
01236 config("vsep_querystr"),
01237 config("safe_querystr")
01238 )
01239 );
01240 }
01241
01242
01243 void
01244 UrlBase::setQueryParam(const std::string ¶m, const std::string &value)
01245 {
01246 zypp::url::ParamMap pmap( getQueryStringMap(zypp::url::E_DECODED));
01247 pmap[param] = value;
01248 setQueryStringMap(pmap);
01249 }
01250
01251
01252
01253 std::string
01254 UrlBase::cleanupPathName(const std::string &path) const
01255 {
01256 bool authority = !getHost(zypp::url::E_ENCODED).empty();
01257 return cleanupPathName(path, authority);
01258 }
01259
01260
01261 std::string
01262 UrlBase::cleanupPathName(const std::string &path, bool authority) const
01263 {
01264 std::string copy( path);
01265
01266
01267 if(copy.size() >= 3 && copy.at(0) != '/' &&
01268 str::toLower(copy.substr(0, 3)) == "%2f")
01269 {
01270 copy.replace(0, 3, "/");
01271 }
01272
01273
01274
01275
01276
01277 if( authority)
01278 {
01279
01280
01281
01282 if(config("path_encode_slash2") == "y")
01283 {
01284
01285 if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
01286 {
01287 copy.replace(1, 1, "%2F");
01288 }
01289 }
01290 else
01291 {
01292
01293 if(copy.size() >= 4 && copy.at(0) == '/' &&
01294 str::toLower(copy.substr(1, 4)) == "%2f")
01295 {
01296 copy.replace(1, 4, "/");
01297 }
01298 }
01299 }
01300 else
01301 {
01302
01303 if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
01304 {
01305 copy.replace(1, 1, "%2F");
01306 }
01307 }
01308 return copy;
01309 }
01310
01311
01312
01313 bool
01314 UrlBase::isValidHost(const std::string &host) const
01315 {
01316 try
01317 {
01318 str::regex regx(RX_VALID_HOSTIPV6);
01319 if( str::regex_match(host, regx))
01320 {
01321 struct in6_addr ip;
01322 std::string temp( host.substr(1, host.size()-2));
01323
01324 return inet_pton(AF_INET6, temp.c_str(), &ip) > 0;
01325 }
01326 else
01327 {
01328
01329 std::string temp( zypp::url::decode(host));
01330 str::regex regx(RX_VALID_HOSTNAME);
01331 return str::regex_match(temp, regx);
01332 }
01333 }
01334 catch( ... )
01335 {}
01336
01337 return false;
01338 }
01339
01340
01341
01342 bool
01343 UrlBase::isValidPort(const std::string &port) const
01344 {
01345 try
01346 {
01347 str::regex regx(RX_VALID_PORT);
01348 if( str::regex_match(port, regx))
01349 {
01350 long pnum = str::strtonum<long>(port);
01351 return ( pnum >= 1 && pnum <= USHRT_MAX);
01352 }
01353 }
01354 catch( ... )
01355 {}
01356 return false;
01357 }
01358
01359
01361 }
01363
01365 }
01367
01368
01369