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