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