00001
00002
00003
00004
00005
00006
00007
00008
00013 #include <iostream>
00014 #include <list>
00015
00016 #include "zypp/base/Logger.h"
00017 #include "zypp/ExternalProgram.h"
00018 #include "zypp/base/String.h"
00019 #include "zypp/base/Gettext.h"
00020 #include "zypp/base/Sysconfig.h"
00021 #include "zypp/base/Gettext.h"
00022
00023 #include "zypp/media/MediaCurl.h"
00024 #include "zypp/media/proxyinfo/ProxyInfos.h"
00025 #include "zypp/media/ProxyInfo.h"
00026 #include "zypp/media/MediaUserAuth.h"
00027 #include "zypp/media/CredentialManager.h"
00028 #include "zypp/media/CurlConfig.h"
00029 #include "zypp/thread/Once.h"
00030 #include "zypp/Target.h"
00031 #include "zypp/ZYppFactory.h"
00032 #include "zypp/ZConfig.h"
00033
00034 #include <cstdlib>
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037 #include <sys/mount.h>
00038 #include <errno.h>
00039 #include <dirent.h>
00040 #include <unistd.h>
00041 #include <boost/format.hpp>
00042
00043 #define DETECT_DIR_INDEX 0
00044 #define CONNECT_TIMEOUT 60
00045 #define TRANSFER_TIMEOUT_MAX 60 * 60
00046
00047 #define EXPLICITLY_NO_PROXY "_none_"
00048
00049 #undef CURLVERSION_AT_LEAST
00050 #define CURLVERSION_AT_LEAST(M,N,O) LIBCURL_VERSION_NUM >= ((((M)<<8)+(N))<<8)+(O)
00051
00052 using namespace std;
00053 using namespace zypp::base;
00054
00055 namespace
00056 {
00057 zypp::thread::OnceFlag g_InitOnceFlag = PTHREAD_ONCE_INIT;
00058 zypp::thread::OnceFlag g_FreeOnceFlag = PTHREAD_ONCE_INIT;
00059
00060 extern "C" void _do_free_once()
00061 {
00062 curl_global_cleanup();
00063 }
00064
00065 extern "C" void globalFreeOnce()
00066 {
00067 zypp::thread::callOnce(g_FreeOnceFlag, _do_free_once);
00068 }
00069
00070 extern "C" void _do_init_once()
00071 {
00072 CURLcode ret = curl_global_init( CURL_GLOBAL_ALL );
00073 if ( ret != 0 )
00074 {
00075 WAR << "curl global init failed" << endl;
00076 }
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 }
00087
00088 inline void globalInitOnce()
00089 {
00090 zypp::thread::callOnce(g_InitOnceFlag, _do_init_once);
00091 }
00092
00093 int log_curl(CURL *curl, curl_infotype info,
00094 char *ptr, size_t len, void *max_lvl)
00095 {
00096 std::string pfx(" ");
00097 long lvl = 0;
00098 switch( info)
00099 {
00100 case CURLINFO_TEXT: lvl = 1; pfx = "*"; break;
00101 case CURLINFO_HEADER_IN: lvl = 2; pfx = "<"; break;
00102 case CURLINFO_HEADER_OUT: lvl = 2; pfx = ">"; break;
00103 default: break;
00104 }
00105 if( lvl > 0 && max_lvl != NULL && lvl <= *((long *)max_lvl))
00106 {
00107 std::string msg(ptr, len);
00108 std::list<std::string> lines;
00109 std::list<std::string>::const_iterator line;
00110 zypp::str::split(msg, std::back_inserter(lines), "\r\n");
00111 for(line = lines.begin(); line != lines.end(); ++line)
00112 {
00113 DBG << pfx << " " << *line << endl;
00114 }
00115 }
00116 return 0;
00117 }
00118
00119 static size_t
00120 log_redirects_curl(
00121 void *ptr, size_t size, size_t nmemb, void *stream)
00122 {
00123
00124
00125 char * lstart = (char *)ptr, * lend = (char *)ptr;
00126 size_t pos = 0;
00127 size_t max = size * nmemb;
00128 while (pos + 1 < max)
00129 {
00130
00131 for (lstart = lend; *lend != '\n' && pos < max; ++lend, ++pos);
00132
00133
00134 string line(lstart, lend);
00135 if (line.find("Location") != string::npos)
00136 {
00137 DBG << "redirecting to " << line << endl;
00138 return max;
00139 }
00140
00141
00142 if (pos + 1 < max)
00143 {
00144 ++lend;
00145 ++pos;
00146 }
00147 else
00148 break;
00149 }
00150
00151 return max;
00152 }
00153 }
00154
00155 namespace zypp {
00156 namespace media {
00157
00158 namespace {
00159 struct ProgressData
00160 {
00161 ProgressData(const long _timeout, const zypp::Url &_url = zypp::Url(),
00162 callback::SendReport<DownloadProgressReport> *_report=NULL)
00163 : timeout(_timeout)
00164 , reached(false)
00165 , report(_report)
00166 , drate_period(-1)
00167 , dload_period(0)
00168 , secs(0)
00169 , drate_avg(-1)
00170 , ltime( time(NULL))
00171 , dload( 0)
00172 , uload( 0)
00173 , url(_url)
00174 {}
00175 long timeout;
00176 bool reached;
00177 callback::SendReport<DownloadProgressReport> *report;
00178
00179 double drate_period;
00180
00181 double dload_period;
00182
00183 long secs;
00184
00185 double drate_avg;
00186
00187 time_t ltime;
00188
00189 double dload;
00190
00191 double uload;
00192 zypp::Url url;
00193 };
00194
00196
00197 inline void escape( string & str_r,
00198 const char char_r, const string & escaped_r ) {
00199 for ( string::size_type pos = str_r.find( char_r );
00200 pos != string::npos; pos = str_r.find( char_r, pos ) ) {
00201 str_r.replace( pos, 1, escaped_r );
00202 }
00203 }
00204
00205 inline string escapedPath( string path_r ) {
00206 escape( path_r, ' ', "%20" );
00207 return path_r;
00208 }
00209
00210 inline string unEscape( string text_r ) {
00211 char * tmp = curl_unescape( text_r.c_str(), 0 );
00212 string ret( tmp );
00213 curl_free( tmp );
00214 return ret;
00215 }
00216
00217 }
00218
00223 void fillSettingsFromUrl( const Url &url, TransferSettings &s )
00224 {
00225 std::string param(url.getQueryParam("timeout"));
00226 if( !param.empty())
00227 {
00228 long num = str::strtonum<long>(param);
00229 if( num >= 0 && num <= TRANSFER_TIMEOUT_MAX)
00230 s.setTimeout(num);
00231 }
00232
00233 if ( ! url.getUsername().empty() )
00234 {
00235 s.setUsername(url.getUsername());
00236 if ( url.getPassword().size() )
00237 s.setPassword(url.getPassword());
00238 }
00239 else
00240 {
00241
00242 if ( url.getScheme() == "ftp" && s.username().empty() )
00243 s.setAnonymousAuth();
00244 }
00245
00246 if ( url.getScheme() == "https" )
00247 {
00248 s.setVerifyPeerEnabled(false);
00249 s.setVerifyHostEnabled(false);
00250
00251 std::string verify( url.getQueryParam("ssl_verify"));
00252 if( verify.empty() ||
00253 verify == "yes")
00254 {
00255 s.setVerifyPeerEnabled(true);
00256 s.setVerifyHostEnabled(true);
00257 }
00258 else if( verify == "no")
00259 {
00260 s.setVerifyPeerEnabled(false);
00261 s.setVerifyHostEnabled(false);
00262 }
00263 else
00264 {
00265 std::vector<std::string> flags;
00266 std::vector<std::string>::const_iterator flag;
00267 str::split( verify, std::back_inserter(flags), ",");
00268 for(flag = flags.begin(); flag != flags.end(); ++flag)
00269 {
00270 if( *flag == "host")
00271 s.setVerifyHostEnabled(true);
00272 else if( *flag == "peer")
00273 s.setVerifyPeerEnabled(true);
00274 else
00275 ZYPP_THROW(MediaBadUrlException(url, "Unknown ssl_verify flag"));
00276 }
00277 }
00278 }
00279
00280 Pathname ca_path = Pathname(url.getQueryParam("ssl_capath")).asString();
00281 if( ! ca_path.empty())
00282 {
00283 if( !PathInfo(ca_path).isDir() || !Pathname(ca_path).absolute())
00284 ZYPP_THROW(MediaBadUrlException(url, "Invalid ssl_capath path"));
00285 else
00286 s.setCertificateAuthoritiesPath(ca_path);
00287 }
00288
00289 string proxy = url.getQueryParam( "proxy" );
00290 if ( ! proxy.empty() )
00291 {
00292 if ( proxy == EXPLICITLY_NO_PROXY ) {
00293
00294
00295
00296
00297 s.setProxy(EXPLICITLY_NO_PROXY);
00298 s.setProxyEnabled(false);
00299 }
00300 else {
00301 string proxyport( url.getQueryParam( "proxyport" ) );
00302 if ( ! proxyport.empty() ) {
00303 proxy += ":" + proxyport;
00304 }
00305 s.setProxy(proxy);
00306 s.setProxyEnabled(true);
00307 }
00308 }
00309
00310
00311 string use_auth = url.getQueryParam("auth");
00312 if (!use_auth.empty() && (url.getScheme() == "http" || url.getScheme() == "https"))
00313 {
00314 try
00315 {
00316 CurlAuthData::auth_type_str2long(use_auth);
00317 }
00318 catch (MediaException & ex_r)
00319 {
00320 DBG << "Rethrowing as MediaUnauthorizedException.";
00321 ZYPP_THROW(MediaUnauthorizedException(url, ex_r.msg(), "", ""));
00322 }
00323 s.setAuthType(use_auth);
00324 }
00325
00326
00327 std::string head_requests( url.getQueryParam("head_requests"));
00328 if( !head_requests.empty() && head_requests == "no")
00329 s.setHeadRequestsAllowed(false);
00330 }
00331
00336 void fillSettingsSystemProxy( const Url&url, TransferSettings &s )
00337 {
00338 ProxyInfo proxy_info (ProxyInfo::ImplPtr(new ProxyInfoSysconfig("proxy")));
00339 s.setProxyEnabled( proxy_info.useProxyFor( url ) );
00340 if ( s.proxyEnabled() )
00341 s.setProxy(proxy_info.proxy(url.getScheme()));
00342 }
00343
00344 Pathname MediaCurl::_cookieFile = "/var/lib/YaST2/cookies";
00345
00350 static const char *const anonymousIdHeader()
00351 {
00352
00353
00354
00355
00356 static const std::string _value(
00357 str::trim( str::form(
00358 "X-ZYpp-AnonymousId: %s",
00359 Target::anonymousUniqueId( Pathname() ).c_str() ) )
00360 );
00361 return _value.c_str();
00362 }
00363
00368 static const char *const distributionFlavorHeader()
00369 {
00370
00371
00372
00373
00374 static const std::string _value(
00375 str::trim( str::form(
00376 "X-ZYpp-DistributionFlavor: %s",
00377 Target::distributionFlavor( Pathname() ).c_str() ) )
00378 );
00379 return _value.c_str();
00380 }
00381
00386 static const char *const agentString()
00387 {
00388
00389
00390
00391
00392 static const std::string _value(
00393 str::form(
00394 "ZYpp %s (curl %s) %s"
00395 , VERSION
00396 , curl_version_info(CURLVERSION_NOW)->version
00397 , Target::targetDistribution( Pathname() ).c_str()
00398 )
00399 );
00400 return _value.c_str();
00401 }
00402
00403
00404
00406 #define SET_OPTION(opt,val) do { \
00407 ret = curl_easy_setopt ( _curl, opt, val ); \
00408 if ( ret != 0) { \
00409 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); \
00410 } \
00411 } while ( false )
00412
00413 #define SET_OPTION_OFFT(opt,val) SET_OPTION(opt,(curl_off_t)val)
00414 #define SET_OPTION_LONG(opt,val) SET_OPTION(opt,(long)val)
00415 #define SET_OPTION_VOID(opt,val) SET_OPTION(opt,(void*)val)
00416
00417 MediaCurl::MediaCurl( const Url & url_r,
00418 const Pathname & attach_point_hint_r )
00419 : MediaHandler( url_r, attach_point_hint_r,
00420 "/",
00421 true ),
00422 _curl( NULL ),
00423 _customHeaders(0L)
00424 {
00425 _curlError[0] = '\0';
00426 _curlDebug = 0L;
00427
00428 MIL << "MediaCurl::MediaCurl(" << url_r << ", " << attach_point_hint_r << ")" << endl;
00429
00430 globalInitOnce();
00431
00432 if( !attachPoint().empty())
00433 {
00434 PathInfo ainfo(attachPoint());
00435 Pathname apath(attachPoint() + "XXXXXX");
00436 char *atemp = ::strdup( apath.asString().c_str());
00437 char *atest = NULL;
00438 if( !ainfo.isDir() || !ainfo.userMayRWX() ||
00439 atemp == NULL || (atest=::mkdtemp(atemp)) == NULL)
00440 {
00441 WAR << "attach point " << ainfo.path()
00442 << " is not useable for " << url_r.getScheme() << endl;
00443 setAttachPoint("", true);
00444 }
00445 else if( atest != NULL)
00446 ::rmdir(atest);
00447
00448 if( atemp != NULL)
00449 ::free(atemp);
00450 }
00451 }
00452
00453 TransferSettings & MediaCurl::settings()
00454 {
00455 return _settings;
00456 }
00457
00458
00459 void MediaCurl::setCookieFile( const Pathname &fileName )
00460 {
00461 _cookieFile = fileName;
00462 }
00463
00465
00466 void MediaCurl::checkProtocol(const Url &url) const
00467 {
00468 curl_version_info_data *curl_info = NULL;
00469 curl_info = curl_version_info(CURLVERSION_NOW);
00470
00471 if (curl_info->protocols)
00472 {
00473 const char * const *proto;
00474 std::string scheme( url.getScheme());
00475 bool found = false;
00476 for(proto=curl_info->protocols; !found && *proto; ++proto)
00477 {
00478 if( scheme == std::string((const char *)*proto))
00479 found = true;
00480 }
00481 if( !found)
00482 {
00483 std::string msg("Unsupported protocol '");
00484 msg += scheme;
00485 msg += "'";
00486 ZYPP_THROW(MediaBadUrlException(_url, msg));
00487 }
00488 }
00489 }
00490
00491 void MediaCurl::setupEasy()
00492 {
00493 {
00494 char *ptr = getenv("ZYPP_MEDIA_CURL_DEBUG");
00495 _curlDebug = (ptr && *ptr) ? str::strtonum<long>( ptr) : 0L;
00496 if( _curlDebug > 0)
00497 {
00498 curl_easy_setopt( _curl, CURLOPT_VERBOSE, 1L);
00499 curl_easy_setopt( _curl, CURLOPT_DEBUGFUNCTION, log_curl);
00500 curl_easy_setopt( _curl, CURLOPT_DEBUGDATA, &_curlDebug);
00501 }
00502 }
00503
00504 curl_easy_setopt(_curl, CURLOPT_HEADERFUNCTION, log_redirects_curl);
00505 CURLcode ret = curl_easy_setopt( _curl, CURLOPT_ERRORBUFFER, _curlError );
00506 if ( ret != 0 ) {
00507 ZYPP_THROW(MediaCurlSetOptException(_url, "Error setting error buffer"));
00508 }
00509
00510 SET_OPTION(CURLOPT_FAILONERROR, 1L);
00511 SET_OPTION(CURLOPT_NOSIGNAL, 1L);
00512
00513
00514
00515 TransferSettings vol_settings(_settings);
00516
00517
00518 vol_settings.addHeader(anonymousIdHeader());
00519 vol_settings.addHeader(distributionFlavorHeader());
00520 vol_settings.addHeader("Pragma:");
00521
00522 _settings.setTimeout(ZConfig::instance().download_transfer_timeout());
00523 _settings.setConnectTimeout(CONNECT_TIMEOUT);
00524
00525 _settings.setUserAgentString(agentString());
00526
00527
00528 try
00529 {
00530 fillSettingsFromUrl(_url, _settings);
00531 }
00532 catch ( const MediaException &e )
00533 {
00534 disconnectFrom();
00535 ZYPP_RETHROW(e);
00536 }
00537
00538 if ( _settings.proxy().empty() )
00539 {
00540
00541 fillSettingsSystemProxy(_url, _settings);
00542 }
00543
00547 SET_OPTION(CURLOPT_CONNECTTIMEOUT, _settings.connectTimeout());
00548
00549
00550
00551 SET_OPTION(CURLOPT_FOLLOWLOCATION, 1L);
00552
00553 SET_OPTION(CURLOPT_MAXREDIRS, 6L);
00554
00555 if ( _url.getScheme() == "https" )
00556 {
00557 #if CURLVERSION_AT_LEAST(7,19,4)
00558
00559 SET_OPTION( CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS );
00560 #endif
00561
00562 if( _settings.verifyPeerEnabled() ||
00563 _settings.verifyHostEnabled() )
00564 {
00565 SET_OPTION(CURLOPT_CAPATH, _settings.certificateAuthoritiesPath().c_str());
00566 }
00567
00568 SET_OPTION(CURLOPT_SSL_VERIFYPEER, _settings.verifyPeerEnabled() ? 1L : 0L);
00569 SET_OPTION(CURLOPT_SSL_VERIFYHOST, _settings.verifyHostEnabled() ? 2L : 0L);
00570 }
00571
00572 SET_OPTION(CURLOPT_USERAGENT, _settings.userAgentString().c_str() );
00573
00574
00575
00576
00577
00578
00579
00580
00581 if ( _settings.userPassword().size() )
00582 {
00583 SET_OPTION(CURLOPT_USERPWD, _settings.userPassword().c_str());
00584 string use_auth = _settings.authType();
00585 if (use_auth.empty())
00586 use_auth = "digest,basic";
00587 long auth = CurlAuthData::auth_type_str2long(use_auth);
00588 if( auth != CURLAUTH_NONE)
00589 {
00590 DBG << "Enabling HTTP authentication methods: " << use_auth
00591 << " (CURLOPT_HTTPAUTH=" << auth << ")" << std::endl;
00592 SET_OPTION(CURLOPT_HTTPAUTH, auth);
00593 }
00594 }
00595
00596 if ( _settings.proxyEnabled() )
00597 {
00598 DBG << "Proxy: '" << _settings.proxy() << "'" << endl;
00599 if ( ! _settings.proxy().empty() )
00600 {
00601 SET_OPTION(CURLOPT_PROXY, _settings.proxy().c_str());
00602 SET_OPTION(CURLOPT_PROXYAUTH, CURLAUTH_BASIC|CURLAUTH_DIGEST|CURLAUTH_NTLM );
00603
00604
00605
00606
00607
00608
00609
00610 string proxyuserpwd = _settings.proxyUserPassword();
00611
00612 if ( proxyuserpwd.empty() )
00613 {
00614 CurlConfig curlconf;
00615 CurlConfig::parseConfig(curlconf);
00616 if (curlconf.proxyuserpwd.empty())
00617 DBG << "~/.curlrc does not contain the proxy-user option" << endl;
00618 else
00619 {
00620 proxyuserpwd = curlconf.proxyuserpwd;
00621 DBG << "using proxy-user from ~/.curlrc" << endl;
00622 }
00623 }
00624
00625 proxyuserpwd = unEscape( proxyuserpwd );
00626 if ( ! proxyuserpwd.empty() )
00627 SET_OPTION(CURLOPT_PROXYUSERPWD, proxyuserpwd.c_str());
00628 }
00629 }
00630 #if CURLVERSION_AT_LEAST(7,19,4)
00631 else if ( _settings.proxy() == EXPLICITLY_NO_PROXY )
00632 {
00633
00634
00635 DBG << "Proxy: explicitly NOPROXY" << endl;
00636 SET_OPTION(CURLOPT_NOPROXY, "*");
00637 }
00638 #endif
00639 else
00640 {
00641
00642 DBG << "Proxy: not explicitly set" << endl;
00643 }
00644
00646 if ( _settings.minDownloadSpeed() != 0 )
00647 {
00648 SET_OPTION(CURLOPT_LOW_SPEED_LIMIT, _settings.minDownloadSpeed());
00649
00650 SET_OPTION(CURLOPT_LOW_SPEED_TIME, 10L);
00651 }
00652
00653 #if CURLVERSION_AT_LEAST(7,15,5)
00654 if ( _settings.maxDownloadSpeed() != 0 )
00655 SET_OPTION_OFFT(CURLOPT_MAX_RECV_SPEED_LARGE, _settings.maxDownloadSpeed());
00656 #endif
00657
00658
00659
00660
00661 _currentCookieFile = _cookieFile.asString();
00662 if ( str::strToBool( _url.getQueryParam( "cookies" ), true ) )
00663 SET_OPTION(CURLOPT_COOKIEFILE, _currentCookieFile.c_str() );
00664 else
00665 MIL << "No cookies requested" << endl;
00666 SET_OPTION(CURLOPT_COOKIEJAR, _currentCookieFile.c_str() );
00667 SET_OPTION(CURLOPT_PROGRESSFUNCTION, &progressCallback );
00668 SET_OPTION(CURLOPT_NOPROGRESS, 0L);
00669
00670 #if CURLVERSION_AT_LEAST(7,18,0)
00671
00672 SET_OPTION(CURLOPT_PROXY_TRANSFER_MODE, 1L );
00673 #endif
00674
00675 for ( TransferSettings::Headers::const_iterator it = vol_settings.headersBegin();
00676 it != vol_settings.headersEnd();
00677 ++it )
00678 {
00679 MIL << "HEADER " << *it << std::endl;
00680
00681 _customHeaders = curl_slist_append(_customHeaders, it->c_str());
00682 if ( !_customHeaders )
00683 ZYPP_THROW(MediaCurlInitException(_url));
00684 }
00685
00686 SET_OPTION(CURLOPT_HTTPHEADER, _customHeaders);
00687 }
00688
00690
00691
00692 void MediaCurl::attachTo (bool next)
00693 {
00694 if ( next )
00695 ZYPP_THROW(MediaNotSupportedException(_url));
00696
00697 if ( !_url.isValid() )
00698 ZYPP_THROW(MediaBadUrlException(_url));
00699
00700 checkProtocol(_url);
00701 if( !isUseableAttachPoint(attachPoint()))
00702 {
00703 std::string mountpoint = createAttachPoint().asString();
00704
00705 if( mountpoint.empty())
00706 ZYPP_THROW( MediaBadAttachPointException(url()));
00707
00708 setAttachPoint( mountpoint, true);
00709 }
00710
00711 disconnectFrom();
00712 _curl = curl_easy_init();
00713 if ( !_curl ) {
00714 ZYPP_THROW(MediaCurlInitException(_url));
00715 }
00716 try
00717 {
00718 setupEasy();
00719 }
00720 catch (Exception & ex)
00721 {
00722 disconnectFrom();
00723 ZYPP_RETHROW(ex);
00724 }
00725
00726
00727 MediaSourceRef media( new MediaSource(_url.getScheme(), _url.asString()));
00728 setMediaSource(media);
00729 }
00730
00731 bool
00732 MediaCurl::checkAttachPoint(const Pathname &apoint) const
00733 {
00734 return MediaHandler::checkAttachPoint( apoint, true, true);
00735 }
00736
00738
00739 void MediaCurl::disconnectFrom()
00740 {
00741 if ( _customHeaders )
00742 {
00743 curl_slist_free_all(_customHeaders);
00744 _customHeaders = 0L;
00745 }
00746
00747 if ( _curl )
00748 {
00749 curl_easy_cleanup( _curl );
00750 _curl = NULL;
00751 }
00752 }
00753
00755
00756 void MediaCurl::releaseFrom( const std::string & ejectDev )
00757 {
00758 disconnect();
00759 }
00760
00761 Url MediaCurl::getFileUrl( const Pathname & filename_r ) const
00762 {
00763 std::string path( _url.getPathName() );
00764
00765
00766
00767
00768
00769
00770 if ( path.empty() || path == "/" )
00771 {
00772 path = filename_r.absolutename().asString();
00773 }
00774 else if ( *path.rbegin() == '/' )
00775 {
00776 path += filename_r.absolutename().asString().substr(1);
00777 }
00778 else
00779 {
00780 path += filename_r.absolutename().asString();
00781 }
00782 Url newurl( _url );
00783 newurl.setPathName( path );
00784 return newurl;
00785 }
00786
00788
00789 void MediaCurl::getFile( const Pathname & filename ) const
00790 {
00791
00792
00793 getFileCopy(filename, localPath(filename).absolutename());
00794 }
00795
00797
00798 void MediaCurl::getFileCopy( const Pathname & filename , const Pathname & target) const
00799 {
00800 callback::SendReport<DownloadProgressReport> report;
00801
00802 Url fileurl(getFileUrl(filename));
00803
00804 bool retry = false;
00805
00806 do
00807 {
00808 try
00809 {
00810 doGetFileCopy(filename, target, report);
00811 retry = false;
00812 }
00813
00814 catch (MediaUnauthorizedException & ex_r)
00815 {
00816 if(authenticate(ex_r.hint(), !retry))
00817 retry = true;
00818 else
00819 {
00820 report->finish(fileurl, zypp::media::DownloadProgressReport::ACCESS_DENIED, ex_r.asUserHistory());
00821 ZYPP_RETHROW(ex_r);
00822 }
00823 }
00824
00825 catch (MediaException & excpt_r)
00826 {
00827
00828 report->finish(fileurl, zypp::media::DownloadProgressReport::ERROR, excpt_r.asUserHistory());
00829 ZYPP_RETHROW(excpt_r);
00830 }
00831 }
00832 while (retry);
00833
00834 report->finish(fileurl, zypp::media::DownloadProgressReport::NO_ERROR, "");
00835 }
00836
00838
00839 bool MediaCurl::getDoesFileExist( const Pathname & filename ) const
00840 {
00841 bool retry = false;
00842
00843 do
00844 {
00845 try
00846 {
00847 return doGetDoesFileExist( filename );
00848 }
00849
00850 catch (MediaUnauthorizedException & ex_r)
00851 {
00852 if(authenticate(ex_r.hint(), !retry))
00853 retry = true;
00854 else
00855 ZYPP_RETHROW(ex_r);
00856 }
00857
00858 catch (MediaException & excpt_r)
00859 {
00860 ZYPP_RETHROW(excpt_r);
00861 }
00862 }
00863 while (retry);
00864
00865 return false;
00866 }
00867
00869
00870 void MediaCurl::evaluateCurlCode( const Pathname &filename,
00871 CURLcode code,
00872 bool timeout_reached ) const
00873 {
00874 if ( code != 0 )
00875 {
00876 Url url;
00877 if (filename.empty())
00878 url = _url;
00879 else
00880 url = getFileUrl(filename);
00881 std::string err;
00882 try
00883 {
00884 switch ( code )
00885 {
00886 case CURLE_UNSUPPORTED_PROTOCOL:
00887 case CURLE_URL_MALFORMAT:
00888 case CURLE_URL_MALFORMAT_USER:
00889 err = " Bad URL";
00890 break;
00891 case CURLE_LOGIN_DENIED:
00892 ZYPP_THROW(
00893 MediaUnauthorizedException(url, "Login failed.", _curlError, ""));
00894 break;
00895 case CURLE_HTTP_RETURNED_ERROR:
00896 {
00897 long httpReturnCode = 0;
00898 CURLcode infoRet = curl_easy_getinfo( _curl,
00899 CURLINFO_RESPONSE_CODE,
00900 &httpReturnCode );
00901 if ( infoRet == CURLE_OK )
00902 {
00903 string msg = "HTTP response: " + str::numstring( httpReturnCode );
00904 switch ( httpReturnCode )
00905 {
00906 case 401:
00907 {
00908 string auth_hint = getAuthHint();
00909
00910 DBG << msg << " Login failed (URL: " << url.asString() << ")" << std::endl;
00911 DBG << "MediaUnauthorizedException auth hint: '" << auth_hint << "'" << std::endl;
00912
00913 ZYPP_THROW(MediaUnauthorizedException(
00914 url, "Login failed.", _curlError, auth_hint
00915 ));
00916 }
00917
00918 case 503:
00919 ZYPP_THROW(MediaTemporaryProblemException(url));
00920 case 504:
00921 ZYPP_THROW(MediaTimeoutException(url));
00922 case 403:
00923 {
00924 string msg403;
00925 if (url.asString().find("novell.com") != string::npos)
00926 msg403 = _("Visit the Novell Customer Center to check whether your registration is valid and has not expired.");
00927 ZYPP_THROW(MediaForbiddenException(url, msg403));
00928 }
00929 case 404:
00930 ZYPP_THROW(MediaFileNotFoundException(_url, filename));
00931 }
00932
00933 DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
00934 ZYPP_THROW(MediaCurlException(url, msg, _curlError));
00935 }
00936 else
00937 {
00938 string msg = "Unable to retrieve HTTP response:";
00939 DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
00940 ZYPP_THROW(MediaCurlException(url, msg, _curlError));
00941 }
00942 }
00943 break;
00944 case CURLE_FTP_COULDNT_RETR_FILE:
00945 #if CURLVERSION_AT_LEAST(7,16,0)
00946 case CURLE_REMOTE_FILE_NOT_FOUND:
00947 #endif
00948 case CURLE_FTP_ACCESS_DENIED:
00949 err = "File not found";
00950 ZYPP_THROW(MediaFileNotFoundException(_url, filename));
00951 break;
00952 case CURLE_BAD_PASSWORD_ENTERED:
00953 case CURLE_FTP_USER_PASSWORD_INCORRECT:
00954 err = "Login failed";
00955 break;
00956 case CURLE_COULDNT_RESOLVE_PROXY:
00957 case CURLE_COULDNT_RESOLVE_HOST:
00958 case CURLE_COULDNT_CONNECT:
00959 case CURLE_FTP_CANT_GET_HOST:
00960 err = "Connection failed";
00961 break;
00962 case CURLE_WRITE_ERROR:
00963 err = "Write error";
00964 break;
00965 case CURLE_PARTIAL_FILE:
00966 case CURLE_OPERATION_TIMEDOUT:
00967 timeout_reached = true;
00968
00969 case CURLE_ABORTED_BY_CALLBACK:
00970 if( timeout_reached )
00971 {
00972 err = "Timeout reached";
00973 ZYPP_THROW(MediaTimeoutException(url));
00974 }
00975 else
00976 {
00977 err = "User abort";
00978 }
00979 break;
00980 case CURLE_SSL_PEER_CERTIFICATE:
00981 default:
00982 err = "Unrecognized error";
00983 break;
00984 }
00985
00986
00987 ZYPP_THROW(MediaCurlException(url, err, _curlError));
00988 }
00989 catch (const MediaException & excpt_r)
00990 {
00991 ZYPP_RETHROW(excpt_r);
00992 }
00993 }
00994 else
00995 {
00996
00997 }
00998 }
00999
01001
01002 bool MediaCurl::doGetDoesFileExist( const Pathname & filename ) const
01003 {
01004 DBG << filename.asString() << endl;
01005
01006 if(!_url.isValid())
01007 ZYPP_THROW(MediaBadUrlException(_url));
01008
01009 if(_url.getHost().empty())
01010 ZYPP_THROW(MediaBadUrlEmptyHostException(_url));
01011
01012 Url url(getFileUrl(filename));
01013
01014 DBG << "URL: " << url.asString() << endl;
01015
01016
01017
01018
01019 Url curlUrl( url );
01020
01021
01022 curlUrl.setUsername( "" );
01023 curlUrl.setPassword( "" );
01024 curlUrl.setPathParams( "" );
01025 curlUrl.setQueryString( "" );
01026 curlUrl.setFragment( "" );
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036 string urlBuffer( curlUrl.asString());
01037 CURLcode ret = curl_easy_setopt( _curl, CURLOPT_URL,
01038 urlBuffer.c_str() );
01039 if ( ret != 0 ) {
01040 ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
01041 }
01042
01043
01044
01045
01046
01047
01048 if ( (_url.getScheme() == "http" || _url.getScheme() == "https") &&
01049 _settings.headRequestsAllowed() )
01050 ret = curl_easy_setopt( _curl, CURLOPT_NOBODY, 1L );
01051 else
01052 ret = curl_easy_setopt( _curl, CURLOPT_RANGE, "0-1" );
01053
01054 if ( ret != 0 ) {
01055 curl_easy_setopt( _curl, CURLOPT_NOBODY, 0L);
01056 curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
01057
01058
01059
01060
01061
01062 curl_easy_setopt( _curl, CURLOPT_HTTPGET, 1L );
01063 ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
01064 }
01065
01066 FILE *file = ::fopen( "/dev/null", "w" );
01067 if ( !file ) {
01068 ERR << "fopen failed for /dev/null" << endl;
01069 curl_easy_setopt( _curl, CURLOPT_NOBODY, 0L);
01070 curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
01071
01072
01073
01074
01075
01076 curl_easy_setopt( _curl, CURLOPT_HTTPGET, 1L );
01077 if ( ret != 0 ) {
01078 ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
01079 }
01080 ZYPP_THROW(MediaWriteException("/dev/null"));
01081 }
01082
01083 ret = curl_easy_setopt( _curl, CURLOPT_WRITEDATA, file );
01084 if ( ret != 0 ) {
01085 ::fclose(file);
01086 std::string err( _curlError);
01087 curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
01088 curl_easy_setopt( _curl, CURLOPT_NOBODY, 0L);
01089
01090
01091
01092
01093
01094 curl_easy_setopt( _curl, CURLOPT_HTTPGET, 1L );
01095 if ( ret != 0 ) {
01096 ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
01097 }
01098 ZYPP_THROW(MediaCurlSetOptException(url, err));
01099 }
01100
01101 CURLcode ok = curl_easy_perform( _curl );
01102 MIL << "perform code: " << ok << " [ " << curl_easy_strerror(ok) << " ]" << endl;
01103
01104
01105 if ( _url.getScheme() == "http" || _url.getScheme() == "https" )
01106 {
01107 curl_easy_setopt( _curl, CURLOPT_NOBODY, 0L);
01108 if ( ret != 0 ) {
01109 ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
01110 }
01111
01112
01113
01114
01115
01116
01117 curl_easy_setopt( _curl, CURLOPT_HTTPGET, 1L);
01118 if ( ret != 0 ) {
01119 ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
01120 }
01121
01122 }
01123 else
01124 {
01125
01126 curl_easy_setopt( _curl, CURLOPT_RANGE, NULL);
01127 if ( ret != 0 ) {
01128 ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
01129 }
01130 }
01131
01132
01133 if ( ok != 0 )
01134 ::fclose(file);
01135
01136
01137
01138
01139 try {
01140 evaluateCurlCode( filename, ok, true );
01141 }
01142 catch ( const MediaFileNotFoundException &e ) {
01143
01144 return false;
01145 }
01146 catch ( const MediaException &e ) {
01147
01148 ZYPP_RETHROW(e);
01149 }
01150
01151 return ( ok == CURLE_OK );
01152 }
01153
01155
01156
01157 #if DETECT_DIR_INDEX
01158 bool MediaCurl::detectDirIndex() const
01159 {
01160 if(_url.getScheme() != "http" && _url.getScheme() != "https")
01161 return false;
01162
01163
01164
01165
01166
01167
01168
01169
01170 bool not_a_file = false;
01171 char *ptr = NULL;
01172 CURLcode ret = curl_easy_getinfo( _curl,
01173 CURLINFO_EFFECTIVE_URL,
01174 &ptr);
01175 if ( ret == CURLE_OK && ptr != NULL)
01176 {
01177 try
01178 {
01179 Url eurl( ptr);
01180 std::string path( eurl.getPathName());
01181 if( !path.empty() && path != "/" && *path.rbegin() == '/')
01182 {
01183 DBG << "Effective url ("
01184 << eurl
01185 << ") seems to provide the index of a directory"
01186 << endl;
01187 not_a_file = true;
01188 }
01189 }
01190 catch( ... )
01191 {}
01192 }
01193 return not_a_file;
01194 }
01195 #endif
01196
01198
01199 void MediaCurl::doGetFileCopy( const Pathname & filename , const Pathname & target, callback::SendReport<DownloadProgressReport> & report, RequestOptions options ) const
01200 {
01201 Pathname dest = target.absolutename();
01202 if( assert_dir( dest.dirname() ) )
01203 {
01204 DBG << "assert_dir " << dest.dirname() << " failed" << endl;
01205 Url url(getFileUrl(filename));
01206 ZYPP_THROW( MediaSystemException(url, "System error on " + dest.dirname().asString()) );
01207 }
01208 string destNew = target.asString() + ".new.zypp.XXXXXX";
01209 char *buf = ::strdup( destNew.c_str());
01210 if( !buf)
01211 {
01212 ERR << "out of memory for temp file name" << endl;
01213 Url url(getFileUrl(filename));
01214 ZYPP_THROW(MediaSystemException(url, "out of memory for temp file name"));
01215 }
01216
01217 int tmp_fd = ::mkstemp( buf );
01218 if( tmp_fd == -1)
01219 {
01220 free( buf);
01221 ERR << "mkstemp failed for file '" << destNew << "'" << endl;
01222 ZYPP_THROW(MediaWriteException(destNew));
01223 }
01224 destNew = buf;
01225 free( buf);
01226
01227 FILE *file = ::fdopen( tmp_fd, "w" );
01228 if ( !file ) {
01229 ::close( tmp_fd);
01230 filesystem::unlink( destNew );
01231 ERR << "fopen failed for file '" << destNew << "'" << endl;
01232 ZYPP_THROW(MediaWriteException(destNew));
01233 }
01234
01235 DBG << "dest: " << dest << endl;
01236 DBG << "temp: " << destNew << endl;
01237
01238
01239 if( PathInfo(target).isExist() && !(options & OPTION_NO_IFMODSINCE) )
01240 {
01241 curl_easy_setopt(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
01242 curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, (long)PathInfo(target).mtime());
01243 }
01244 else
01245 {
01246 curl_easy_setopt(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
01247 curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, 0L);
01248 }
01249 try
01250 {
01251 doGetFileCopyFile(filename, dest, file, report, options);
01252 }
01253 catch (Exception &e)
01254 {
01255 ::fclose( file );
01256 filesystem::unlink( destNew );
01257 curl_easy_setopt(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
01258 curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, 0L);
01259 ZYPP_RETHROW(e);
01260 }
01261
01262 long httpReturnCode = 0;
01263 CURLcode infoRet = curl_easy_getinfo(_curl,
01264 CURLINFO_RESPONSE_CODE,
01265 &httpReturnCode);
01266 bool modified = true;
01267 if (infoRet == CURLE_OK)
01268 {
01269 DBG << "HTTP response: " + str::numstring(httpReturnCode);
01270 if ( httpReturnCode == 304
01271 || ( httpReturnCode == 213 && _url.getScheme() == "ftp" ) )
01272 {
01273 DBG << " Not modified.";
01274 modified = false;
01275 }
01276 DBG << endl;
01277 }
01278 else
01279 {
01280 WAR << "Could not get the reponse code." << endl;
01281 }
01282
01283 if (modified || infoRet != CURLE_OK)
01284 {
01285
01286 if ( ::fchmod( ::fileno(file), filesystem::applyUmaskTo( 0644 ) ) )
01287 {
01288 ERR << "Failed to chmod file " << destNew << endl;
01289 }
01290 if (::fclose( file ))
01291 {
01292 ERR << "Fclose failed for file '" << destNew << "'" << endl;
01293 ZYPP_THROW(MediaWriteException(destNew));
01294 }
01295
01296 if ( rename( destNew, dest ) != 0 ) {
01297 ERR << "Rename failed" << endl;
01298 ZYPP_THROW(MediaWriteException(dest));
01299 }
01300 }
01301 else
01302 {
01303
01304 ::fclose( file );
01305 filesystem::unlink( destNew );
01306 }
01307
01308 DBG << "done: " << PathInfo(dest) << endl;
01309 }
01310
01312
01313 void MediaCurl::doGetFileCopyFile( const Pathname & filename , const Pathname & dest, FILE *file, callback::SendReport<DownloadProgressReport> & report, RequestOptions options ) const
01314 {
01315 DBG << filename.asString() << endl;
01316
01317 if(!_url.isValid())
01318 ZYPP_THROW(MediaBadUrlException(_url));
01319
01320 if(_url.getHost().empty())
01321 ZYPP_THROW(MediaBadUrlEmptyHostException(_url));
01322
01323 Url url(getFileUrl(filename));
01324
01325 DBG << "URL: " << url.asString() << endl;
01326
01327
01328
01329
01330 Url curlUrl( url );
01331
01332
01333 curlUrl.setUsername( "" );
01334 curlUrl.setPassword( "" );
01335 curlUrl.setPathParams( "" );
01336 curlUrl.setQueryString( "" );
01337 curlUrl.setFragment( "" );
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347 string urlBuffer( curlUrl.asString());
01348 CURLcode ret = curl_easy_setopt( _curl, CURLOPT_URL,
01349 urlBuffer.c_str() );
01350 if ( ret != 0 ) {
01351 ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
01352 }
01353
01354 ret = curl_easy_setopt( _curl, CURLOPT_WRITEDATA, file );
01355 if ( ret != 0 ) {
01356 ZYPP_THROW(MediaCurlSetOptException(url, _curlError));
01357 }
01358
01359
01360 ProgressData progressData(_settings.timeout(), url, &report);
01361 if (!(options & OPTION_NO_REPORT_START))
01362 report->start(url, dest);
01363 if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, &progressData ) != 0 ) {
01364 WAR << "Can't set CURLOPT_PROGRESSDATA: " << _curlError << endl;;
01365 }
01366
01367 ret = curl_easy_perform( _curl );
01368
01369 if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, NULL ) != 0 ) {
01370 WAR << "Can't unset CURLOPT_PROGRESSDATA: " << _curlError << endl;;
01371 }
01372
01373 if ( ret != 0 )
01374 {
01375 ERR << "curl error: " << ret << ": " << _curlError
01376 << ", temp file size " << ftell(file)
01377 << " bytes." << endl;
01378
01379
01380
01381
01382 try {
01383 evaluateCurlCode( filename, ret, progressData.reached);
01384 }
01385 catch ( const MediaException &e ) {
01386
01387 ZYPP_RETHROW(e);
01388 }
01389 }
01390
01391 #if DETECT_DIR_INDEX
01392 if (!ret && detectDirIndex())
01393 {
01394 ZYPP_THROW(MediaNotAFileException(_url, filename));
01395 }
01396 #endif // DETECT_DIR_INDEX
01397 }
01398
01400
01401 void MediaCurl::getDir( const Pathname & dirname, bool recurse_r ) const
01402 {
01403 filesystem::DirContent content;
01404 getDirInfo( content, dirname, false );
01405
01406 for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
01407 Pathname filename = dirname + it->name;
01408 int res = 0;
01409
01410 switch ( it->type ) {
01411 case filesystem::FT_NOT_AVAIL:
01412 case filesystem::FT_FILE:
01413 getFile( filename );
01414 break;
01415 case filesystem::FT_DIR:
01416 if ( recurse_r ) {
01417 getDir( filename, recurse_r );
01418 } else {
01419 res = assert_dir( localPath( filename ) );
01420 if ( res ) {
01421 WAR << "Ignore error (" << res << ") on creating local directory '" << localPath( filename ) << "'" << endl;
01422 }
01423 }
01424 break;
01425 default:
01426
01427 break;
01428 }
01429 }
01430 }
01431
01433
01434 void MediaCurl::getDirInfo( std::list<std::string> & retlist,
01435 const Pathname & dirname, bool dots ) const
01436 {
01437 getDirectoryYast( retlist, dirname, dots );
01438 }
01439
01441
01442 void MediaCurl::getDirInfo( filesystem::DirContent & retlist,
01443 const Pathname & dirname, bool dots ) const
01444 {
01445 getDirectoryYast( retlist, dirname, dots );
01446 }
01447
01449
01450 int MediaCurl::progressCallback( void *clientp,
01451 double dltotal, double dlnow,
01452 double ultotal, double ulnow)
01453 {
01454 ProgressData *pdata = reinterpret_cast<ProgressData *>(clientp);
01455 if( pdata)
01456 {
01457 time_t now = time(NULL);
01458 if( now > 0)
01459 {
01460
01461
01462 if( pdata->ltime <= 0 || pdata->ltime > now)
01463 {
01464 pdata->ltime = now;
01465 }
01466
01467
01468
01469 time_t dif = 0;
01470 if (dlnow > 0 || ulnow > 0)
01471 {
01472 dif = (now - pdata->ltime);
01473 dif = dif > 0 ? dif : 0;
01474
01475 pdata->secs += dif;
01476 }
01477
01478
01479
01480
01481
01483
01484 if ( pdata->secs > 1 && (dif > 0 || dlnow == dltotal ))
01485 pdata->drate_avg = (dlnow / pdata->secs);
01486
01487 if ( dif > 0 )
01488 {
01489 pdata->drate_period = ((dlnow - pdata->dload_period) / dif);
01490 pdata->dload_period = dlnow;
01491 }
01492 }
01493
01494
01495 if( pdata->report)
01496 {
01497 if (!(*(pdata->report))->progress(int( dltotal ? dlnow * 100 / dltotal : 0 ),
01498 pdata->url,
01499 pdata->drate_avg,
01500 pdata->drate_period))
01501 {
01502 return 1;
01503 }
01504 }
01505
01506
01507 if( pdata->timeout > 0)
01508 {
01509 if( now > 0)
01510 {
01511 bool progress = false;
01512
01513
01514 if( dlnow != pdata->dload)
01515 {
01516 progress = true;
01517 pdata->dload = dlnow;
01518 pdata->ltime = now;
01519 }
01520
01521 if( ulnow != pdata->uload)
01522 {
01523 progress = true;
01524 pdata->uload = ulnow;
01525 pdata->ltime = now;
01526 }
01527
01528 if( !progress && (now >= (pdata->ltime + pdata->timeout)))
01529 {
01530 pdata->reached = true;
01531 return 1;
01532 }
01533 }
01534 }
01535 }
01536 return 0;
01537 }
01538
01540
01541 string MediaCurl::getAuthHint() const
01542 {
01543 long auth_info = CURLAUTH_NONE;
01544
01545 CURLcode infoRet =
01546 curl_easy_getinfo(_curl, CURLINFO_HTTPAUTH_AVAIL, &auth_info);
01547
01548 if(infoRet == CURLE_OK)
01549 {
01550 return CurlAuthData::auth_type_long2str(auth_info);
01551 }
01552
01553 return "";
01554 }
01555
01557
01558 bool MediaCurl::authenticate(const string & availAuthTypes, bool firstTry) const
01559 {
01561 Target_Ptr target = zypp::getZYpp()->getTarget();
01562 CredentialManager cm(CredManagerOptions(target ? target->root() : ""));
01563 CurlAuthData_Ptr credentials;
01564
01565
01566 AuthData_Ptr cmcred = cm.getCred(_url);
01567
01568 if (cmcred && firstTry)
01569 {
01570 credentials.reset(new CurlAuthData(*cmcred));
01571 DBG << "got stored credentials:" << endl << *credentials << endl;
01572 }
01573
01574 else
01575 {
01576
01577 CurlAuthData_Ptr curlcred;
01578 curlcred.reset(new CurlAuthData());
01579 callback::SendReport<AuthenticationReport> auth_report;
01580
01581
01582 if (!_url.getUsername().empty() && firstTry)
01583 curlcred->setUsername(_url.getUsername());
01584
01585 else if (cmcred)
01586 curlcred->setUsername(cmcred->username());
01587
01588
01589 cmcred.reset();
01590
01591 string prompt_msg = boost::str(boost::format(
01593 _("Authentication required for '%s'")) % _url.asString());
01594
01595
01596
01597 curlcred->setAuthType(availAuthTypes);
01598
01599
01600 if (auth_report->prompt(_url, prompt_msg, *curlcred))
01601 {
01602 DBG << "callback answer: retry" << endl
01603 << "CurlAuthData: " << *curlcred << endl;
01604
01605 if (curlcred->valid())
01606 {
01607 credentials = curlcred;
01608
01609
01617 }
01618 }
01619 else
01620 {
01621 DBG << "callback answer: cancel" << endl;
01622 }
01623 }
01624
01625
01626 if (credentials)
01627 {
01628
01629 const_cast<MediaCurl*>(this)->_settings.setUsername(credentials->username());
01630 const_cast<MediaCurl*>(this)->_settings.setPassword(credentials->password());
01631
01632
01633 CURLcode ret = curl_easy_setopt(_curl, CURLOPT_USERPWD, _settings.userPassword().c_str());
01634 if ( ret != 0 ) ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
01635
01636
01637 if (credentials->authType() == CURLAUTH_NONE)
01638 credentials->setAuthType(availAuthTypes);
01639
01640
01641 if (credentials->authType() != CURLAUTH_NONE)
01642 {
01643
01644 const_cast<MediaCurl*>(this)->_settings.setAuthType(credentials->authTypeAsString());
01645 ret = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, credentials->authType());
01646 if ( ret != 0 ) ZYPP_THROW(MediaCurlSetOptException(_url, _curlError));
01647 }
01648
01649 if (!cmcred)
01650 {
01651 credentials->setUrl(_url);
01652 cm.addCred(*credentials);
01653 cm.save();
01654 }
01655
01656 return true;
01657 }
01658
01659 return false;
01660 }
01661
01662
01663 }
01664 }
01665