libzypp
10.5.0
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 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 // in the Estonian locale, a-z excludes t, for example. #302525 00027 // http://en.wikipedia.org/wiki/Estonian_alphabet 00028 #define a_zA_Z "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 00029 00030 // --------------------------------------------------------------- 00031 /* 00032 ** authority = //[user [:password] @ ] host [:port] 00033 ** 00034 ** host = hostname | IPv4 | "[" IPv6-IP "]" | "[v...]" 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 ** URL asString() view option constants: 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 const ViewOption ViewOption::DEFAULTS = 00079 ViewOption::WITH_SCHEME + 00080 ViewOption::WITH_USERNAME + 00081 ViewOption::WITH_HOST + 00082 ViewOption::WITH_PORT + 00083 ViewOption::WITH_PATH_NAME + 00084 ViewOption::WITH_QUERY_STR + 00085 ViewOption::WITH_FRAGMENT + 00086 ViewOption::EMPTY_AUTHORITY + 00087 ViewOption::EMPTY_PATH_NAME; 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 ** Behaviour configuration variables. 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 ** Anonymous/internal utility namespace: 00140 */ 00141 namespace // anonymous 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 } // namespace 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 // y=yes (allowed) 00262 // n=no (disallowed, exception if !empty) 00263 config("with_authority", "y"); 00264 config("with_port", "y"); 00265 00266 // y=yes (required but don't throw if empty) 00267 // n=no (not required, ignore if empty) 00268 // m=mandatory (exception if empty) 00269 config("require_host", "n"); 00270 config("require_pathname","n"); 00271 00272 // y=yes (encode 2. slash even if authority present) 00273 // n=no (don't encode 2. slash if authority present) 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 ** scheme is the only mandatory component 00406 ** for all url's and is already verified, 00407 ** (except for empty Url instances), so 00408 ** Url with empty scheme is never valid. 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 ** path has to begin with "/" if authority avaliable 00423 ** if host is set after the pathname, we can't throw 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 // Url contains authority (that may be empty), 00511 // we may need a rewrite of the encoded path. 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 // always decode in case isValidHost() 01027 // is reimplemented and supports also 01028 // the [v ... ] notation. 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 // has to begin with a "/". For consistency with 01108 // setPathName while the host is empty, we allow 01109 // it in encoded ("%2f") form - cleanupPathName() 01110 // will fix / decode the first slash if needed. 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 // zypp::url::E_DECODED 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 void 01251 UrlBase::delQueryParam(const std::string ¶m) 01252 { 01253 zypp::url::ParamMap pmap( getQueryStringMap(zypp::url::E_DECODED)); 01254 pmap.erase(param); 01255 setQueryStringMap(pmap); 01256 } 01257 01258 01259 // --------------------------------------------------------------- 01260 std::string 01261 UrlBase::cleanupPathName(const std::string &path) const 01262 { 01263 bool authority = !getHost(zypp::url::E_ENCODED).empty(); 01264 return cleanupPathName(path, authority); 01265 } 01266 01267 // --------------------------------------------------------------- 01268 std::string 01269 UrlBase::cleanupPathName(const std::string &path, bool authority) const 01270 { 01271 std::string copy( path); 01272 01273 // decode the first slash if it is encoded ... 01274 if(copy.size() >= 3 && copy.at(0) != '/' && 01275 str::toLower(copy.substr(0, 3)) == "%2f") 01276 { 01277 copy.replace(0, 3, "/"); 01278 } 01279 01280 // if path begins with a double slash ("//"); encode the second 01281 // slash [minimal and IMO sufficient] before the first path 01282 // segment, to fulfill the path-absolute rule of RFC 3986 01283 // disallowing a "//" if no authority is present. 01284 if( authority) 01285 { 01286 // 01287 // rewrite of "//" to "/%2f" not required, use config 01288 // 01289 if(config("path_encode_slash2") == "y") 01290 { 01291 // rewrite "//" ==> "/%2f" 01292 if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/') 01293 { 01294 copy.replace(1, 1, "%2F"); 01295 } 01296 } 01297 else 01298 { 01299 // rewrite "/%2f" ==> "//" 01300 if(copy.size() >= 4 && copy.at(0) == '/' && 01301 str::toLower(copy.substr(1, 4)) == "%2f") 01302 { 01303 copy.replace(1, 4, "/"); 01304 } 01305 } 01306 } 01307 else 01308 { 01309 // rewrite of "//" to "/%2f" is required (no authority) 01310 if(copy.size() >= 2 && copy.at(0) == '/' && copy.at(1) == '/') 01311 { 01312 copy.replace(1, 1, "%2F"); 01313 } 01314 } 01315 return copy; 01316 } 01317 01318 01319 // --------------------------------------------------------------- 01320 bool 01321 UrlBase::isValidHost(const std::string &host) const 01322 { 01323 try 01324 { 01325 str::regex regx(RX_VALID_HOSTIPV6); 01326 if( str::regex_match(host, regx)) 01327 { 01328 struct in6_addr ip; 01329 std::string temp( host.substr(1, host.size()-2)); 01330 01331 return inet_pton(AF_INET6, temp.c_str(), &ip) > 0; 01332 } 01333 else 01334 { 01335 // matches also IPv4 dotted-decimal adresses... 01336 std::string temp( zypp::url::decode(host)); 01337 str::regex regx(RX_VALID_HOSTNAME); 01338 return str::regex_match(temp, regx); 01339 } 01340 } 01341 catch( ... ) 01342 {} 01343 01344 return false; 01345 } 01346 01347 01348 // --------------------------------------------------------------- 01349 bool 01350 UrlBase::isValidPort(const std::string &port) const 01351 { 01352 try 01353 { 01354 str::regex regx(RX_VALID_PORT); 01355 if( str::regex_match(port, regx)) 01356 { 01357 long pnum = str::strtonum<long>(port); 01358 return ( pnum >= 1 && pnum <= USHRT_MAX); 01359 } 01360 } 01361 catch( ... ) 01362 {} 01363 return false; 01364 } 01365 01366 01368 } // namespace url 01370 01372 } // namespace zypp 01374 /* 01375 ** vim: set ts=2 sts=2 sw=2 ai et: 01376 */