From 4cba0723fb6f61ea1b4a0d91bc0dfcfec5b43bbd Mon Sep 17 00:00:00 2001 From: Duncan Mac-Vicar P Date: Sun, 22 Feb 2009 02:00:25 +0100 Subject: [PATCH] big MediaCurl refactoring, to share the settings initialization with MediaAria2c. - replace lot of curl_easy_setop with exception checking to a macro to reduce duplicated code - implement download.min_download_speed (default no limit) download.max_download_speed (default no limit) for MediaCurl as well Still thinking if MediaCurl should be still the default for https, because aria does not support a CA dir (only files) --- zypp/media/MediaAria2c.cc | 152 ------------ zypp/media/MediaAria2c.h | 2 - zypp/media/MediaCurl.cc | 546 ++++++++++++++++++----------------------- zypp/media/MediaCurl.h | 27 +- zypp/media/TransferSettings.cc | 64 +++++ zypp/media/TransferSettings.h | 48 ++++ 6 files changed, 368 insertions(+), 471 deletions(-) diff --git a/zypp/media/MediaAria2c.cc b/zypp/media/MediaAria2c.cc index e9d04e4..8d00e78 100644 --- a/zypp/media/MediaAria2c.cc +++ b/zypp/media/MediaAria2c.cc @@ -26,7 +26,6 @@ #include "zypp/Target.h" #include "zypp/ZYppFactory.h" -#include "zypp/media/TransferProgram.h" #include "zypp/media/MediaAria2c.h" #include "zypp/media/proxyinfo/ProxyInfos.h" #include "zypp/media/ProxyInfo.h" @@ -75,84 +74,6 @@ MediaAria2c::existsAria2cmd() return ( aria.close() == 0 ); } -void fillSettingsFromUrl( const Url &url, TransferSettings &s ) -{ - std::string param(url.getQueryParam("timeout")); - if( !param.empty()) - { - long num = str::strtonum(param); - if( num >= 0 && num <= TRANSFER_TIMEOUT_MAX) - s.setTimeout(num); - } - - if ( ! url.getUsername().empty() ) - { - s.setUsername(url.getUsername()); - if ( url.getPassword().size() ) - { - s.setPassword(url.getPassword()); - } - } - - string proxy = url.getQueryParam( "proxy" ); - - if ( ! proxy.empty() ) - { - string proxyport( url.getQueryParam( "proxyport" ) ); - if ( ! proxyport.empty() ) { - proxy += ":" + proxyport; - } - s.setProxy(proxy); - s.setProxyEnabled(true); - } -} - -void fillSettingsSystemProxy( const Url&url, TransferSettings &s ) -{ - ProxyInfo proxy_info (ProxyInfo::ImplPtr(new ProxyInfoSysconfig("proxy"))); - - if ( proxy_info.enabled()) - { - s.setProxyEnabled(true); - std::list nope = proxy_info.noProxy(); - for (ProxyInfo::NoProxyIterator it = proxy_info.noProxyBegin(); - it != proxy_info.noProxyEnd(); - it++) - { - std::string host( str::toLower(url.getHost())); - std::string temp( str::toLower(*it)); - - // no proxy if it points to a suffix - // preceeded by a '.', that maches - // the trailing portion of the host. - if( temp.size() > 1 && temp.at(0) == '.') - { - if(host.size() > temp.size() && - host.compare(host.size() - temp.size(), temp.size(), temp) == 0) - { - DBG << "NO_PROXY: '" << *it << "' matches host '" - << host << "'" << endl; - s.setProxyEnabled(false); - break; - } - } - else - // no proxy if we have an exact match - if( host == temp) - { - DBG << "NO_PROXY: '" << *it << "' matches host '" - << host << "'" << endl; - s.setProxyEnabled(false); - break; - } - } - - if ( s.proxyEnabled() ) - s.setProxy(proxy_info.proxy(url.getScheme())); - } - -} - /** * comannd line for aria. * The argument list gets passed as reference @@ -250,38 +171,6 @@ void fillAriaCmdLine( const Pathname &ariapath, args.push_back(url.asString().c_str()); } -static const char *const anonymousIdHeader() -{ - // we need to add the release and identifier to the - // agent string. - // The target could be not initialized, and then this information - // is not available. - Target_Ptr target = zypp::getZYpp()->getTarget(); - - static const std::string _value( - str::form( - "X-Zypp-AnonymousId: %s", - target ? target->anonymousUniqueId().c_str() : "" ) - ); - return _value.c_str(); -} - -static const char *const distributionFlavorHeader() -{ - // we need to add the release and identifier to the - // agent string. - // The target could be not initialized, and then this information - // is not available. - Target_Ptr target = zypp::getZYpp()->getTarget(); - - static const std::string _value( - str::trim( str::form( - "X-ZYpp-DistributionFlavor: %s", - target ? target->distributionFlavor().c_str() : "" ) ) - ); - return _value.c_str(); -} - const char *const MediaAria2c::agentString() { // we need to add the release and identifier to the @@ -309,28 +198,6 @@ MediaAria2c::MediaAria2c( const Url & url_r, { MIL << "MediaAria2c::MediaAria2c(" << url_r << ", " << attach_point_hint_r << ")" << endl; - /* - if( !attachPoint().empty()) - { - PathInfo ainfo(attachPoint()); - Pathname apath(attachPoint() + "XXXXXX"); - char *atemp = ::strdup( apath.asString().c_str()); - char *atest = NULL; - if( !ainfo.isDir() || !ainfo.userMayRWX() || - atemp == NULL || (atest=::mkdtemp(atemp)) == NULL) - { - WAR << "attach point " << ainfo.path() - << " is not useable for " << url_r.getScheme() << endl; - setAttachPoint("", true); - } - else if( atest != NULL) - ::rmdir(atest); - - if( atemp != NULL) - ::free(atemp); - } - */ - //At this point, we initialize aria2c path _aria2cPath = Pathname( whereisAria2c().asString() ); @@ -341,25 +208,7 @@ MediaAria2c::MediaAria2c( const Url & url_r, void MediaAria2c::attachTo (bool next) { MediaCurl::attachTo(next); - _settings.setUserAgentString(agentString()); - _settings.addHeader(anonymousIdHeader()); - _settings.addHeader(distributionFlavorHeader()); - - _settings.setTimeout(TRANSFER_TIMEOUT); - _settings.setConnectTimeout(CONNECT_TIMEOUT); - - // fill some settings from url query parameters - fillSettingsFromUrl(_url, _settings); - - // if the proxy was not set by url, then look - if ( _settings.proxy().empty() ) - { - // at the system proxy settings - fillSettingsSystemProxy(_url, _settings); - } - - DBG << "Proxy: " << (_settings.proxy().empty() ? "-none-" : _settings.proxy()) << endl; } bool @@ -371,7 +220,6 @@ MediaAria2c::checkAttachPoint(const Pathname &apoint) const void MediaAria2c::disconnectFrom() { MediaCurl::disconnectFrom(); - } void MediaAria2c::releaseFrom( const std::string & ejectDev ) diff --git a/zypp/media/MediaAria2c.h b/zypp/media/MediaAria2c.h index 33d49f7..544cc8f 100644 --- a/zypp/media/MediaAria2c.h +++ b/zypp/media/MediaAria2c.h @@ -107,8 +107,6 @@ class MediaAria2c : public MediaCurl { /** External process to get aria2c version */ std::string getAria2cVersion(); static std::string _aria2cVersion; - - TransferSettings _settings; }; /////////////////////////////////////////////////////////////////// diff --git a/zypp/media/MediaCurl.cc b/zypp/media/MediaCurl.cc index 280c9a7..af797d2 100644 --- a/zypp/media/MediaCurl.cc +++ b/zypp/media/MediaCurl.cc @@ -183,6 +183,129 @@ namespace zypp { // /////////////////////////////////////////////////////////////////// +void fillSettingsFromUrl( const Url &url, TransferSettings &s ) +{ + std::string param(url.getQueryParam("timeout")); + if( !param.empty()) + { + long num = str::strtonum(param); + if( num >= 0 && num <= TRANSFER_TIMEOUT_MAX) + s.setTimeout(num); + } + + if ( ! url.getUsername().empty() ) + { + s.setUsername(url.getUsername()); + if ( url.getPassword().size() ) + s.setPassword(url.getPassword()); + } + else + { + // if there is no username, set anonymous auth + if ( url.getScheme() == "ftp" && s.username().empty() ) + s.setAnonymousAuth(); + } + + if ( url.getScheme() == "https" ) + { + s.setVerifyPeerEnabled(false); + s.setVerifyHostEnabled(false); + + std::string verify( url.getQueryParam("ssl_verify")); + if( verify.empty() || + verify == "yes") + { + s.setVerifyPeerEnabled(true); + s.setVerifyHostEnabled(true); + } + else if( verify == "no") + { + s.setVerifyPeerEnabled(false); + s.setVerifyHostEnabled(false); + } + else + { + std::vector flags; + std::vector::const_iterator flag; + str::split( verify, std::back_inserter(flags), ","); + for(flag = flags.begin(); flag != flags.end(); ++flag) + { + if( *flag == "host") + s.setVerifyHostEnabled(true); + else if( *flag == "peer") + s.setVerifyPeerEnabled(true); + else + ZYPP_THROW(MediaBadUrlException(url, "Unknown ssl_verify flag")); + } + } + } + + Pathname ca_path = Pathname(url.getQueryParam("ssl_capath")).asString(); + if( ! ca_path.empty()) + { + if( !PathInfo(ca_path).isDir() || !Pathname(ca_path).absolute()) + ZYPP_THROW(MediaBadUrlException(url, "Invalid ssl_capath path")); + else + s.setCertificateAuthoritiesPath(ca_path); + } + + string proxy = url.getQueryParam( "proxy" ); + if ( ! proxy.empty() ) + { + string proxyport( url.getQueryParam( "proxyport" ) ); + if ( ! proxyport.empty() ) { + proxy += ":" + proxyport; + } + s.setProxy(proxy); + s.setProxyEnabled(true); + } +} + +void fillSettingsSystemProxy( const Url&url, TransferSettings &s ) +{ + ProxyInfo proxy_info (ProxyInfo::ImplPtr(new ProxyInfoSysconfig("proxy"))); + + if ( proxy_info.enabled()) + { + s.setProxyEnabled(true); + std::list nope = proxy_info.noProxy(); + for (ProxyInfo::NoProxyIterator it = proxy_info.noProxyBegin(); + it != proxy_info.noProxyEnd(); + it++) + { + std::string host( str::toLower(url.getHost())); + std::string temp( str::toLower(*it)); + + // no proxy if it points to a suffix + // preceeded by a '.', that maches + // the trailing portion of the host. + if( temp.size() > 1 && temp.at(0) == '.') + { + if(host.size() > temp.size() && + host.compare(host.size() - temp.size(), temp.size(), temp) == 0) + { + DBG << "NO_PROXY: '" << *it << "' matches host '" + << host << "'" << endl; + s.setProxyEnabled(false); + break; + } + } + else + // no proxy if we have an exact match + if( host == temp) + { + DBG << "NO_PROXY: '" << *it << "' matches host '" + << host << "'" << endl; + s.setProxyEnabled(false); + break; + } + } + + if ( s.proxyEnabled() ) + s.setProxy(proxy_info.proxy(url.getScheme())); + } +} + Pathname MediaCurl::_cookieFile = "/var/lib/YaST2/cookies"; static const char *const anonymousIdHeader() @@ -217,7 +340,6 @@ static const char *const distributionFlavorHeader() return _value.c_str(); } - static const char *const agentString() { // we need to add the release and identifier to the @@ -237,7 +359,15 @@ static const char *const agentString() return _value.c_str(); } - +// we use this define to unbloat code +#define SET_OPTION(opt,val) { \ + ret = curl_easy_setopt ( _curl, opt, val ); \ + if ( ret != 0) { \ + disconnectFrom(); \ + ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); \ + } \ + } + MediaCurl::MediaCurl( const Url & url_r, const Pathname & attach_point_hint_r ) : MediaHandler( url_r, attach_point_hint_r, @@ -280,13 +410,7 @@ void MediaCurl::setCookieFile( const Pathname &fileName ) } /////////////////////////////////////////////////////////////////// -// -// -// METHOD NAME : MediaCurl::attachTo -// METHOD TYPE : PMError -// -// DESCRIPTION : Asserted that not already attached, and attachPoint is a directory. -// + void MediaCurl::attachTo (bool next) { if ( next ) @@ -353,148 +477,66 @@ void MediaCurl::attachTo (bool next) ZYPP_THROW(MediaCurlSetOptException(_url, "Error setting error buffer")); } - ret = curl_easy_setopt( _curl, CURLOPT_FAILONERROR, true ); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } + SET_OPTION(CURLOPT_FAILONERROR,true); + SET_OPTION(CURLOPT_NOSIGNAL, 1); - ret = curl_easy_setopt( _curl, CURLOPT_NOSIGNAL, 1 ); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } + // add custom headers + _settings.addHeader(anonymousIdHeader()); + _settings.addHeader(distributionFlavorHeader()); + _settings.addHeader("Pragma:"); - /** - * Transfer timeout - */ - { - _xfer_timeout = TRANSFER_TIMEOUT; + _settings.setTimeout(TRANSFER_TIMEOUT); + _settings.setConnectTimeout(CONNECT_TIMEOUT); - std::string param(_url.getQueryParam("timeout")); - if( !param.empty()) - { - long num = str::strtonum( param); - if( num >= 0 && num <= TRANSFER_TIMEOUT_MAX) - _xfer_timeout = num; - } - } + _settings.setUserAgentString(agentString()); - /* - ** Connect timeout - */ - ret = curl_easy_setopt( _curl, CURLOPT_CONNECTTIMEOUT, CONNECT_TIMEOUT); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); + // fill some settings from url query parameters + try + { + fillSettingsFromUrl(_url, _settings); } - - if ( _url.getScheme() == "http" ) { - // follow any Location: header that the server sends as part of - // an HTTP header (#113275) - ret = curl_easy_setopt ( _curl, CURLOPT_FOLLOWLOCATION, true ); - if ( ret != 0) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } - ret = curl_easy_setopt ( _curl, CURLOPT_MAXREDIRS, 3L ); - if ( ret != 0) { + catch ( const MediaException &e ) + { disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } + ZYPP_RETHROW(e); + } + + // if the proxy was not set by url, then look + if ( _settings.proxy().empty() ) + { + // at the system proxy settings + fillSettingsSystemProxy(_url, _settings); + } - ret = curl_easy_setopt ( _curl, CURLOPT_USERAGENT, agentString() ); + DBG << "Proxy: " << (_settings.proxy().empty() ? "-none-" : _settings.proxy()) << endl; + /** + * Connect timeout + */ + SET_OPTION(CURLOPT_CONNECTTIMEOUT, _settings.connectTimeout()); - if ( ret != 0) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } + if ( _url.getScheme() == "http" ) + { + // follow any Location: header that the server sends as part of + // an HTTP header (#113275) + SET_OPTION(CURLOPT_FOLLOWLOCATION, true); + SET_OPTION(CURLOPT_MAXREDIRS, 3L); + SET_OPTION(CURLOPT_USERAGENT, _settings.userAgentString().c_str() ); } if ( _url.getScheme() == "https" ) { - bool verify_peer = false; - bool verify_host = false; - - std::string verify( _url.getQueryParam("ssl_verify")); - if( verify.empty() || - verify == "yes") - { - verify_peer = true; - verify_host = true; - } - else - if( verify == "no") - { - verify_peer = false; - verify_host = false; - } - else - { - std::vector flags; - std::vector::const_iterator flag; - str::split( verify, std::back_inserter(flags), ","); - for(flag = flags.begin(); flag != flags.end(); ++flag) - { - if( *flag == "host") - { - verify_host = true; - } - else - if( *flag == "peer") - { - verify_peer = true; - } - else - { - disconnectFrom(); - ZYPP_THROW(MediaBadUrlException(_url, "Unknown ssl_verify flag")); - } - } - } - - _ca_path = Pathname(_url.getQueryParam("ssl_capath")).asString(); - if( _ca_path.empty()) - { - _ca_path = "/etc/ssl/certs/"; - } - else - if( !PathInfo(_ca_path).isDir() || !Pathname(_ca_path).absolute()) - { - disconnectFrom(); - ZYPP_THROW(MediaBadUrlException(_url, "Invalid ssl_capath path")); - } - - if( verify_peer || verify_host) + if( _settings.verifyPeerEnabled() || + _settings.verifyHostEnabled() ) { - ret = curl_easy_setopt( _curl, CURLOPT_CAPATH, _ca_path.c_str()); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } - } - - ret = curl_easy_setopt( _curl, CURLOPT_SSL_VERIFYPEER, verify_peer ? 1L : 0L); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } - ret = curl_easy_setopt( _curl, CURLOPT_SSL_VERIFYHOST, verify_host ? 2L : 0L); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } - - ret = curl_easy_setopt ( _curl, CURLOPT_USERAGENT, agentString() ); - if ( ret != 0) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); + SET_OPTION(CURLOPT_CAPATH, _settings.certificateAuthoritiesPath().c_str()); } + SET_OPTION(CURLOPT_SSL_VERIFYPEER, _settings.verifyPeerEnabled() ? 1L : 0L); + SET_OPTION(CURLOPT_SSL_VERIFYHOST, _settings.verifyHostEnabled() ? 2L : 0L); + SET_OPTION(CURLOPT_USERAGENT, _settings.userAgentString().c_str() ); } - /*---------------------------------------------------------------* CURLOPT_USERPWD: [user name]:[password] @@ -502,27 +544,12 @@ void MediaCurl::attachTo (bool next) If not provided, anonymous FTP identification *---------------------------------------------------------------*/ - if ( _url.getUsername().empty() ) { - if ( _url.getScheme() == "ftp" ) { - string id = "yast2@"; - id += VERSION; - DBG << "Anonymous FTP identification: '" << id << "'" << endl; - _userpwd = "anonymous:" + id; - } - } else { - _userpwd = _url.getUsername(); - if ( _url.getPassword().size() ) { - _userpwd += ":" + _url.getPassword(); - } - } + if ( _settings.userPassword().size() ) + { + SET_OPTION(CURLOPT_USERPWD, unEscape(_settings.userPassword()).c_str()); - if ( _userpwd.size() ) { - _userpwd = unEscape( _userpwd ); - ret = curl_easy_setopt( _curl, CURLOPT_USERPWD, _userpwd.c_str() ); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } + //FIXME, we leave this here for now, as it does not make sense yet + // to refactor it to the fill settings from url function // HTTP authentication type if(_url.getScheme() == "http" || _url.getScheme() == "https") @@ -539,11 +566,7 @@ void MediaCurl::attachTo (bool next) DBG << "Enabling HTTP authentication methods: " << use_auth << " (CURLOPT_HTTPAUTH=" << auth << ")" << std::endl; - ret = curl_easy_setopt( _curl, CURLOPT_HTTPAUTH, auth); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } + SET_OPTION(CURLOPT_HTTPAUTH, auth); } } catch (MediaException & ex_r) @@ -560,177 +583,72 @@ void MediaCurl::attachTo (bool next) } } - /*---------------------------------------------------------------* - CURLOPT_PROXY: host[:port] - - Url::option(proxy and proxyport) -> CURLOPT_PROXY - If not provided, /etc/sysconfig/proxy is evaluated - *---------------------------------------------------------------*/ - - _proxy = _url.getQueryParam( "proxy" ); - - if ( ! _proxy.empty() ) { - string proxyport( _url.getQueryParam( "proxyport" ) ); - if ( ! proxyport.empty() ) { - _proxy += ":" + proxyport; - } - } else { - - ProxyInfo proxy_info (ProxyInfo::ImplPtr(new ProxyInfoSysconfig("proxy"))); - - if ( proxy_info.enabled()) + if ( _settings.proxyEnabled() ) + { + if ( ! _settings.proxy().empty() ) { - bool useproxy = true; - - std::list nope = proxy_info.noProxy(); - for (ProxyInfo::NoProxyIterator it = proxy_info.noProxyBegin(); - it != proxy_info.noProxyEnd(); - it++) + SET_OPTION(CURLOPT_PROXY, _settings.proxy().c_str()); + /*---------------------------------------------------------------* + CURLOPT_PROXYUSERPWD: [user name]:[password] + + Url::option(proxyuser and proxypassword) -> CURLOPT_PROXYUSERPWD + If not provided, $HOME/.curlrc is evaluated + *---------------------------------------------------------------*/ + + string proxyuserpwd = _settings.proxyUserPassword(); + + if ( proxyuserpwd.empty() ) { - std::string host( str::toLower(_url.getHost())); - std::string temp( str::toLower(*it)); - - // no proxy if it points to a suffix - // preceeded by a '.', that maches - // the trailing portion of the host. - if( temp.size() > 1 && temp.at(0) == '.') - { - if(host.size() > temp.size() && - host.compare(host.size() - temp.size(), temp.size(), temp) == 0) - { - DBG << "NO_PROXY: '" << *it << "' matches host '" - << host << "'" << endl; - useproxy = false; - break; - } - } + if (curlconf.proxyuserpwd.empty()) + DBG << "~/.curlrc does not contain the proxy-user option" << endl; else - // no proxy if we have an exact match - if( host == temp) { - DBG << "NO_PROXY: '" << *it << "' matches host '" - << host << "'" << endl; - useproxy = false; - break; + proxyuserpwd = curlconf.proxyuserpwd; + DBG << "using proxy-user from ~/.curlrc" << endl; } } - if ( useproxy ) { - _proxy = proxy_info.proxy(_url.getScheme()); - } + proxyuserpwd = unEscape( proxyuserpwd ); + if ( ! proxyuserpwd.empty() ) + SET_OPTION(CURLOPT_PROXYUSERPWD, proxyuserpwd.c_str()); } } - - - DBG << "Proxy: " << (_proxy.empty() ? "-none-" : _proxy) << endl; - - if ( ! _proxy.empty() ) { - - ret = curl_easy_setopt( _curl, CURLOPT_PROXY, _proxy.c_str() ); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } - - /*---------------------------------------------------------------* - CURLOPT_PROXYUSERPWD: [user name]:[password] - - Url::option(proxyuser and proxypassword) -> CURLOPT_PROXYUSERPWD - If not provided, $HOME/.curlrc is evaluated - *---------------------------------------------------------------*/ - - _proxyuserpwd = _url.getQueryParam( "proxyuser" ); - - if ( ! _proxyuserpwd.empty() ) { - string proxypassword( _url.getQueryParam( "proxypassword" ) ); - if ( ! proxypassword.empty() ) { - _proxyuserpwd += ":" + proxypassword; - } - } else { - if (curlconf.proxyuserpwd.empty()) - DBG << "~/.curlrc does not contain the proxy-user option" << endl; - else - { - _proxyuserpwd = curlconf.proxyuserpwd; - DBG << "using proxy-user from ~/.curlrc" << endl; - } - } - - _proxyuserpwd = unEscape( _proxyuserpwd ); - if ( ! _proxyuserpwd.empty() ) { - ret = curl_easy_setopt( _curl, CURLOPT_PROXYUSERPWD, _proxyuserpwd.c_str() ); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } - } + + /** Speed limits */ + if ( _settings.minDownloadSpeed() != 0 ) + { + SET_OPTION(CURLOPT_LOW_SPEED_LIMIT, _settings.minDownloadSpeed()); + // default to 10 seconds at low speed + SET_OPTION(CURLOPT_LOW_SPEED_TIME, 10); } + + if ( _settings.maxDownloadSpeed() != 0 ) + SET_OPTION(CURLOPT_MAX_RECV_SPEED_LARGE, _settings.maxDownloadSpeed()); /*---------------------------------------------------------------* *---------------------------------------------------------------*/ _currentCookieFile = _cookieFile.asString(); - - ret = curl_easy_setopt( _curl, CURLOPT_COOKIEFILE, - _currentCookieFile.c_str() ); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } - - ret = curl_easy_setopt( _curl, CURLOPT_COOKIEJAR, - _currentCookieFile.c_str() ); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } - - ret = curl_easy_setopt( _curl, CURLOPT_PROGRESSFUNCTION, - &progressCallback ); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } - - ret = curl_easy_setopt( _curl, CURLOPT_NOPROGRESS, false ); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } + SET_OPTION(CURLOPT_COOKIEFILE, _currentCookieFile.c_str() ); + SET_OPTION(CURLOPT_COOKIEJAR, _currentCookieFile.c_str() ); + SET_OPTION(CURLOPT_PROGRESSFUNCTION, &progressCallback ); + SET_OPTION(CURLOPT_NOPROGRESS, false ); // bnc #306272 - ret = curl_easy_setopt( _curl, CURLOPT_PROXY_TRANSFER_MODE, 1 ); - if ( ret != 0 ) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } - - _customHeaders = curl_slist_append(_customHeaders, "Pragma:"); - - if ( !_customHeaders ) { - ZYPP_THROW(MediaCurlInitException(_url)); - } - - // now add the anonymous id header - _customHeaders = curl_slist_append(_customHeaders, anonymousIdHeader()); + SET_OPTION(CURLOPT_PROXY_TRANSFER_MODE, 1 ); - if ( !_customHeaders ) { - ZYPP_THROW(MediaCurlInitException(_url)); - } - - // now add the product flavor header - _customHeaders = curl_slist_append(_customHeaders, distributionFlavorHeader()); - - if ( !_customHeaders ) { - ZYPP_THROW(MediaCurlInitException(_url)); + // append settings custom headers to curl + for ( TransferSettings::Headers::const_iterator it = _settings.headersBegin(); + it != _settings.headersEnd(); + ++it ) + { + + _customHeaders = curl_slist_append(_customHeaders, it->c_str()); + if ( !_customHeaders ) + ZYPP_THROW(MediaCurlInitException(_url)); } - ret = curl_easy_setopt ( _curl, CURLOPT_HTTPHEADER, _customHeaders ); - - if ( ret != 0) { - disconnectFrom(); - ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); - } + SET_OPTION(CURLOPT_HTTPHEADER, _customHeaders); // FIXME: need a derived class to propelly compare url's MediaSourceRef media( new MediaSource(_url.getScheme(), _url.asString())); @@ -1163,7 +1081,7 @@ bool MediaCurl::doGetDoesFileExist( const Pathname & filename ) const } -void MediaCurl::doGetFileCopy( const Pathname & filename , const Pathname & target, callback::SendReport & report) const +void MediaCurl::doGetFileCopy( const Pathname & filename , const Pathname & target, callback::SendReport & report, RequestOptions options ) const { DBG << filename.asString() << endl; @@ -1262,7 +1180,7 @@ void MediaCurl::doGetFileCopy( const Pathname & filename , const Pathname & targ } // Set callback and perform. - ProgressData progressData(_xfer_timeout, url, &report); + ProgressData progressData(_settings.timeout(), url, &report); report->start(url, dest); if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, &progressData ) != 0 ) { WAR << "Can't set CURLOPT_PROGRESSDATA: " << _curlError << endl;; @@ -1734,10 +1652,12 @@ bool MediaCurl::authenticate(const string & availAuthTypes, bool firstTry) const // set username and password if (credentials) { - _userpwd = credentials->getUserPwd(); + // HACK, why is this const? + const_cast(this)->_settings.setUsername(credentials->username()); + const_cast(this)->_settings.setPassword(credentials->password()); // set username and password - CURLcode ret = curl_easy_setopt(_curl, CURLOPT_USERPWD, _userpwd.c_str()); + CURLcode ret = curl_easy_setopt(_curl, CURLOPT_USERPWD, _settings.userPassword().c_str()); if ( ret != 0 ) ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); // set available authentication types from the exception diff --git a/zypp/media/MediaCurl.h b/zypp/media/MediaCurl.h index 248341b..6be4bdb 100644 --- a/zypp/media/MediaCurl.h +++ b/zypp/media/MediaCurl.h @@ -12,6 +12,8 @@ #ifndef ZYPP_MEDIA_MEDIACURL_H #define ZYPP_MEDIA_MEDIACURL_H +#include "zypp/base/Flags.h" +#include "zypp/media/TransferSettings.h" #include "zypp/media/MediaHandler.h" #include "zypp/ZYppCallbacks.h" @@ -27,7 +29,19 @@ namespace zypp { * @short Implementation class for FTP, HTTP and HTTPS MediaHandler * @see MediaHandler **/ -class MediaCurl : public MediaHandler { +class MediaCurl : public MediaHandler +{ + public: + enum RequestOption + { + /** Defaults */ + OPTION_NONE = 0x0, + /** retrieve only a range of the file */ + OPTION_RANGE = 0x1, + /** only issue a HEAD (or equivalent) request */ + OPTION_HEAD = 0x02, + }; + ZYPP_DECLARE_FLAGS(RequestOptions,RequestOption); protected: @@ -69,7 +83,7 @@ class MediaCurl : public MediaHandler { * \throws MediaException * */ - virtual void doGetFileCopy( const Pathname & srcFilename, const Pathname & targetFilename, callback::SendReport & _report) const; + virtual void doGetFileCopy( const Pathname & srcFilename, const Pathname & targetFilename, callback::SendReport & _report, RequestOptions options = OPTION_NONE ) const; virtual bool checkAttachPoint(const Pathname &apoint) const; @@ -109,15 +123,20 @@ class MediaCurl : public MediaHandler { long _curlDebug; curl_slist *_customHeaders; + /* mutable std::string _userpwd; std::string _proxy; std::string _proxyuserpwd; + */ std::string _currentCookieFile; - std::string _ca_path; - long _xfer_timeout; + //std::string _ca_path; + //long _xfer_timeout; static Pathname _cookieFile; +protected: + TransferSettings _settings; }; +ZYPP_DECLARE_OPERATORS_FOR_FLAGS(MediaCurl::RequestOptions); /////////////////////////////////////////////////////////////////// diff --git a/zypp/media/TransferSettings.cc b/zypp/media/TransferSettings.cc index b206d1b..e822f27 100644 --- a/zypp/media/TransferSettings.cc +++ b/zypp/media/TransferSettings.cc @@ -32,6 +32,9 @@ public: , _minDownloadSpeed(ZConfig::instance().download_min_download_speed()) , _maxDownloadSpeed(ZConfig::instance().download_max_download_speed()) , _maxSilentTries(ZConfig::instance().download_max_silent_tries()) + , _verify_host(false) + , _verify_peer(false) + , _ca_path("/etc/ssl/certs") {} virtual ~Impl() @@ -68,6 +71,10 @@ public: long _minDownloadSpeed; long _maxDownloadSpeed; long _maxSilentTries; + + bool _verify_host; + bool _verify_peer; + Pathname _ca_path; }; TransferSettings::TransferSettings() @@ -116,11 +123,27 @@ void TransferSettings::setPassword( const std::string &password ) _impl->_password = password; } +void TransferSettings::setAnonymousAuth() +{ + setUsername("anonymous"); + string id = "yast@"; + setPassword(id + VERSION); +} + std::string TransferSettings::password() const { return _impl->_password; } +std::string TransferSettings::userPassword() const +{ + string userpwd = username(); + if ( password().size() ) { + userpwd += ":" + password(); + } + return userpwd; +} + void TransferSettings::setProxyEnabled( bool enabled ) { _impl->_useproxy = enabled; @@ -161,6 +184,15 @@ std::string TransferSettings::proxyPassword() const return _impl->_proxy_password; } +std::string TransferSettings::proxyUserPassword() const +{ + string userpwd = proxyUsername(); + if ( proxyPassword().size() ) { + userpwd += ":" + proxyPassword(); + } + return userpwd; +} + void TransferSettings::setTimeout( long t ) { _impl->_timeout = t; @@ -221,6 +253,38 @@ void TransferSettings::setMaxSilentTries(long v) _impl->_maxSilentTries = v; } +bool TransferSettings::verifyHostEnabled() const +{ + return _impl->_verify_host; +} + +void TransferSettings::setVerifyHostEnabled( bool enabled ) +{ + _impl->_verify_host = enabled; +} + +bool TransferSettings::verifyPeerEnabled() const +{ + return _impl->_verify_peer; +} + + +void TransferSettings::setVerifyPeerEnabled( bool enabled ) +{ + _impl->_verify_peer = enabled; +} + +Pathname TransferSettings::certificateAuthoritiesPath() const +{ + return _impl->_ca_path; +} + +void TransferSettings::setCertificateAuthoritiesPath( const zypp::Pathname &path ) +{ + _impl->_ca_path = path; +} + + } // ns media } // ns zypp diff --git a/zypp/media/TransferSettings.h b/zypp/media/TransferSettings.h index 1491bb7..567fff9 100644 --- a/zypp/media/TransferSettings.h +++ b/zypp/media/TransferSettings.h @@ -79,6 +79,17 @@ public: std::string password() const; /** + * returns the user and password as + * a user:pass string + */ + std::string userPassword() const; + + /** + * sets anonymous authentication (ie: for ftp) + */ + void setAnonymousAuth(); + + /** * whether the proxy is used or not */ void setProxyEnabled( bool enabled ); @@ -119,6 +130,12 @@ public: std::string proxyPassword() const; /** + * returns the proxy user and password as + * a user:pass string + */ + std::string proxyUserPassword() const; + + /** * set the connect timeout */ void setConnectTimeout( long t ); @@ -180,6 +197,37 @@ public: */ void setMaxSilentTries(long v); + /** + * Whether to verify host for ssl + */ + bool verifyHostEnabled() const; + + /** + * Sets whether to verify host for ssl + */ + void setVerifyHostEnabled( bool enabled ); + + /** + * Whether to verify peer for ssl + */ + bool verifyPeerEnabled() const; + + /** + * Sets whether to verify host for ssl + */ + void setVerifyPeerEnabled( bool enabled ); + + /** + * SSL certificate authorities path + * ( default: /etc/ssl/certs ) + */ + Pathname certificateAuthoritiesPath() const; + + /** + * Sets the SSL certificate authorities path + */ + void setCertificateAuthoritiesPath( const zypp::Pathname &path ); + protected: class Impl; RWCOW_pointer _impl; -- 2.7.4