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 if ((p = s.rfind(':')) != std::string::npos && ( (q = s.rfind(']')) == std::string::npos || q < p) )
00854 {
00855 setHost(s.substr(0, p));
00856 setPort(s.substr(p+1));
00857 }
00858 else
00859 setHost(s);
00860 }
00861
00862
00863 void
00864 UrlBase::setPathData(const std::string &pathdata)
00865 {
00866 size_t pos = std::string::npos;
00867 std::string sep(config("sep_pathparams"));
00868
00869 if( !sep.empty())
00870 pos = pathdata.find(sep);
00871
00872 if( pos != std::string::npos)
00873 {
00874 setPathName(pathdata.substr(0, pos),
00875 zypp::url::E_ENCODED);
00876 setPathParams(pathdata.substr(pos + 1));
00877 }
00878 else
00879 {
00880 setPathName(pathdata,
00881 zypp::url::E_ENCODED);
00882 setPathParams("");
00883 }
00884 }
00885
00886
00887
00888 void
00889 UrlBase::setQueryString(const std::string &querystr)
00890 {
00891 if( querystr.empty())
00892 {
00893 m_data->querystr = querystr;
00894 }
00895 else
00896 {
00897 checkUrlData(querystr, "query string", config("rx_querystr"));
00898
00899 m_data->querystr = querystr;
00900 }
00901 }
00902
00903
00904
00905 void
00906 UrlBase::setFragment(const std::string &fragment,
00907 EEncoding eflag)
00908 {
00909 if( fragment.empty())
00910 {
00911 m_data->fragment = fragment;
00912 }
00913 else
00914 {
00915 if(eflag == zypp::url::E_ENCODED)
00916 {
00917 checkUrlData(fragment, "fragment", config("rx_fragment"));
00918
00919 m_data->fragment = fragment;
00920 }
00921 else
00922 {
00923 m_data->fragment = zypp::url::encode(
00924 fragment, config("safe_fragment")
00925 );
00926 }
00927 }
00928 }
00929
00930
00931
00932 void
00933 UrlBase::setUsername(const std::string &user,
00934 EEncoding eflag)
00935 {
00936 if( user.empty())
00937 {
00938 m_data->user = user;
00939 }
00940 else
00941 {
00942 if( config("with_authority") != "y")
00943 {
00944 ZYPP_THROW(UrlNotAllowedException(
00945 _("Url scheme does not allow a username")
00946 ));
00947 }
00948
00949 if(eflag == zypp::url::E_ENCODED)
00950 {
00951 checkUrlData(user, "username", config("rx_username"));
00952
00953 m_data->user = user;
00954 }
00955 else
00956 {
00957 m_data->user = zypp::url::encode(
00958 user, config("safe_username")
00959 );
00960 }
00961 }
00962 }
00963
00964
00965
00966 void
00967 UrlBase::setPassword(const std::string &pass,
00968 EEncoding eflag)
00969 {
00970 if( pass.empty())
00971 {
00972 m_data->pass = pass;
00973 }
00974 else
00975 {
00976 if( config("with_authority") != "y")
00977 {
00978 ZYPP_THROW(UrlNotAllowedException(
00979 _("Url scheme does not allow a password")
00980 ));
00981 }
00982
00983 if(eflag == zypp::url::E_ENCODED)
00984 {
00985 checkUrlData(pass, "password", config("rx_password"), false);
00986
00987 m_data->pass = pass;
00988 }
00989 else
00990 {
00991 m_data->pass = zypp::url::encode(
00992 pass, config("safe_password")
00993 );
00994 }
00995 }
00996 }
00997
00998
00999
01000 void
01001 UrlBase::setHost(const std::string &host)
01002 {
01003 if( host.empty())
01004 {
01005 if(config("require_host") == "m")
01006 {
01007 ZYPP_THROW(UrlNotAllowedException(
01008 _("Url scheme requires a host component")
01009 ));
01010 }
01011 m_data->host = host;
01012 }
01013 else
01014 {
01015 if( config("with_authority") != "y")
01016 {
01017 ZYPP_THROW(UrlNotAllowedException(
01018 _("Url scheme does not allow a host component")
01019 ));
01020 }
01021
01022 if( isValidHost(host))
01023 {
01024 std::string temp;
01025
01026
01027
01028
01029 if( host.at(0) == '[')
01030 {
01031 temp = str::toUpper(zypp::url::decode(host));
01032 }
01033 else
01034 {
01035 temp = str::toLower(zypp::url::decode(host));
01036 }
01037
01038 m_data->host = zypp::url::encode(
01039 temp, config("safe_hostname")
01040 );
01041 }
01042 else
01043 {
01044 ZYPP_THROW(UrlBadComponentException(
01045 str::form(_("Invalid host component '%s'"), host.c_str())
01046 ));
01047 }
01048 }
01049 }
01050
01051
01052
01053 void
01054 UrlBase::setPort(const std::string &port)
01055 {
01056 if( port.empty())
01057 {
01058 m_data->port = port;
01059 }
01060 else
01061 {
01062 if( config("with_authority") != "y" ||
01063 config("with_port") != "y")
01064 {
01065 ZYPP_THROW(UrlNotAllowedException(
01066 _("Url scheme does not allow a port")
01067 ));
01068 }
01069
01070 if( isValidPort(port))
01071 {
01072 m_data->port = port;
01073 }
01074 else
01075 {
01076 ZYPP_THROW(UrlBadComponentException(
01077 str::form(_("Invalid port component '%s'"), port.c_str())
01078 ));
01079 }
01080 }
01081 }
01082
01083
01084
01085 void
01086 UrlBase::setPathName(const std::string &path,
01087 EEncoding eflag)
01088 {
01089 if( path.empty())
01090 {
01091 if(config("require_pathname") == "m")
01092 {
01093 ZYPP_THROW(UrlNotAllowedException(
01094 _("Url scheme requires path name")
01095 ));
01096 }
01097 m_data->pathname = path;
01098 }
01099 else
01100 {
01101 if(eflag == zypp::url::E_ENCODED)
01102 {
01103 checkUrlData(path, "path name", config("rx_pathname"));
01104
01105 if( !getHost(zypp::url::E_ENCODED).empty())
01106 {
01107
01108
01109
01110
01111 if(!(path.at(0) == '/' || (path.size() >= 3 &&
01112 str::toLower(path.substr(0, 3)) == "%2f")))
01113 {
01114 ZYPP_THROW(UrlNotAllowedException(
01115 _("Relative path not allowed if authority exists")
01116 ));
01117 }
01118 }
01119
01120 m_data->pathname = cleanupPathName(path);
01121 }
01122 else
01123 {
01124 if( !getHost(zypp::url::E_ENCODED).empty())
01125 {
01126 if(path.at(0) != '/')
01127 {
01128 ZYPP_THROW(UrlNotAllowedException(
01129 _("Relative path not allowed if authority exists")
01130 ));
01131 }
01132 }
01133
01134 m_data->pathname = cleanupPathName(
01135 zypp::url::encode(
01136 path, config("safe_pathname")
01137 )
01138 );
01139 }
01140 }
01141 }
01142
01143
01144
01145 void
01146 UrlBase::setPathParams(const std::string ¶ms)
01147 {
01148 if( params.empty())
01149 {
01150 m_data->pathparams = params;
01151 }
01152 else
01153 {
01154 checkUrlData(params, "path parameters", config("rx_pathparams"));
01155
01156 m_data->pathparams = params;
01157 }
01158 }
01159
01160
01161
01162 void
01163 UrlBase::setPathParamsVec(const zypp::url::ParamVec &pvec)
01164 {
01165 setPathParams(
01166 zypp::url::join(
01167 pvec,
01168 config("psep_pathparam")
01169 )
01170 );
01171 }
01172
01173
01174
01175 void
01176 UrlBase::setPathParamsMap(const zypp::url::ParamMap &pmap)
01177 {
01178 if( config("psep_pathparam").empty() ||
01179 config("vsep_pathparam").empty())
01180 {
01181 ZYPP_THROW(UrlNotSupportedException(
01182 "Path Parameter parsing not supported for this URL"
01183 ));
01184 }
01185 setPathParams(
01186 zypp::url::join(
01187 pmap,
01188 config("psep_pathparam"),
01189 config("vsep_pathparam"),
01190 config("safe_pathparams")
01191 )
01192 );
01193 }
01194
01195
01196
01197 void
01198 UrlBase::setPathParam(const std::string ¶m, const std::string &value)
01199 {
01200 zypp::url::ParamMap pmap( getPathParamsMap(zypp::url::E_DECODED));
01201 pmap[param] = value;
01202 setPathParamsMap(pmap);
01203 }
01204
01205
01206
01207 void
01208 UrlBase::setQueryStringVec(const zypp::url::ParamVec &pvec)
01209 {
01210 setQueryString(
01211 zypp::url::join(
01212 pvec,
01213 config("psep_querystr")
01214 )
01215 );
01216 }
01217
01218
01219
01220 void
01221 UrlBase::setQueryStringMap(const zypp::url::ParamMap &pmap)
01222 {
01223 if( config("psep_querystr").empty() ||
01224 config("vsep_querystr").empty())
01225 {
01226 ZYPP_THROW(UrlNotSupportedException(
01227 _("Query string parsing not supported for this URL")
01228 ));
01229 }
01230 setQueryString(
01231 zypp::url::join(
01232 pmap,
01233 config("psep_querystr"),
01234 config("vsep_querystr"),
01235 config("safe_querystr")
01236 )
01237 );
01238 }
01239
01240
01241 void
01242 UrlBase::setQueryParam(const std::string ¶m, const std::string &value)
01243 {
01244 zypp::url::ParamMap pmap( getQueryStringMap(zypp::url::E_DECODED));
01245 pmap[param] = value;
01246 setQueryStringMap(pmap);
01247 }
01248
01249
01250
01251 std::string
01252 UrlBase::cleanupPathName(const std::string &path) const
01253 {
01254 bool authority = !getHost(zypp::url::E_ENCODED).empty();
01255 return cleanupPathName(path, authority);
01256 }
01257
01258
01259 std::string
01260 UrlBase::cleanupPathName(const std::string &path, bool authority) const
01261 {
01262 std::string copy( path);
01263
01264
01265 if(copy.size() >= 3 && copy.at(0) != '/' &&
01266 str::toLower(copy.substr(0, 3)) == "%2f")
01267 {
01268 copy.replace(0, 3, "/");
01269 }
01270
01271
01272
01273
01274
01275 if( authority)
01276 {
01277
01278
01279
01280 if(config("path_encode_slash2") == "y")
01281 {
01282
01283 if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
01284 {
01285 copy.replace(1, 1, "%2F");
01286 }
01287 }
01288 else
01289 {
01290
01291 if(copy.size() >= 4 && copy.at(0) == '/' &&
01292 str::toLower(copy.substr(1, 4)) == "%2f")
01293 {
01294 copy.replace(1, 4, "/");
01295 }
01296 }
01297 }
01298 else
01299 {
01300
01301 if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/')
01302 {
01303 copy.replace(1, 1, "%2F");
01304 }
01305 }
01306 return copy;
01307 }
01308
01309
01310
01311 bool
01312 UrlBase::isValidHost(const std::string &host) const
01313 {
01314 try
01315 {
01316 str::regex regx(RX_VALID_HOSTIPV6);
01317 if( str::regex_match(host, regx))
01318 {
01319 struct in6_addr ip;
01320 std::string temp( host.substr(1, host.size()-2));
01321
01322 return inet_pton(AF_INET6, temp.c_str(), &ip) > 0;
01323 }
01324 else
01325 {
01326
01327 std::string temp( zypp::url::decode(host));
01328 str::regex regx(RX_VALID_HOSTNAME);
01329 return str::regex_match(temp, regx);
01330 }
01331 }
01332 catch( ... )
01333 {}
01334
01335 return false;
01336 }
01337
01338
01339
01340 bool
01341 UrlBase::isValidPort(const std::string &port) const
01342 {
01343 try
01344 {
01345 str::regex regx(RX_VALID_PORT);
01346 if( str::regex_match(port, regx))
01347 {
01348 long pnum = str::strtonum<long>(port);
01349 return ( pnum >= 1 && pnum <= USHRT_MAX);
01350 }
01351 }
01352 catch( ... )
01353 {}
01354 return false;
01355 }
01356
01357
01359 }
01361
01363 }
01365
01366
01367