libzypp 17.37.8
MediaCurl.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
12
13#include <iostream>
14#include <chrono>
15#include <list>
16
17#include <zypp/base/Logger.h>
19#include <zypp/base/String.h>
20#include <zypp/base/Gettext.h>
21#include <utility>
22#include <zypp-core/parser/Sysconfig>
23#include <zypp/base/Gettext.h>
24
28#include <zypp-curl/ProxyInfo>
29#include <zypp-curl/auth/CurlAuthData>
30#include <zypp-media/auth/CredentialManager>
31#include <zypp-curl/CurlConfig>
32#include <zypp/Target.h>
33#include <zypp/ZYppFactory.h>
34#include <zypp/ZConfig.h>
35#include <zypp/zypp_detail/ZYppImpl.h> // for zypp_poll
36
37#include <cstdlib>
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <sys/mount.h>
41#include <dirent.h>
42#include <unistd.h>
43#include <glib.h>
44
46
47using std::endl;
48
49namespace internal {
50 using namespace zypp;
52 {
53 ProgressData( CURL *curl, time_t timeout = 0, zypp::Url url = zypp::Url(),
54 zypp::ByteCount expectedFileSize_r = 0,
56
57 void updateStats( curl_off_t dltotal = 0.0, curl_off_t dlnow = 0.0 );
58
59 int reportProgress() const;
60
61 CURL * curl()
62 { return _curl; }
63
64 bool timeoutReached() const
65 { return _timeoutReached; }
66
67 bool fileSizeExceeded() const
68 { return _fileSizeExceeded; }
69
72
73 void expectedFileSize( ByteCount newval_r )
74 { _expectedFileSize = newval_r; }
75
76 zypp::Url url() const
77 { return _url; }
78
79 private:
80 CURL * _curl;
82 time_t _timeout;
87
88 time_t _timeStart = 0;
89 time_t _timeLast = 0;
90 time_t _timeRcv = 0;
91 time_t _timeNow = 0;
92
93 curl_off_t _dnlTotal = 0.0;
94 curl_off_t _dnlLast = 0.0;
95 curl_off_t _dnlNow = 0.0;
96
97 int _dnlPercent= 0;
98
99 double _drateTotal= 0.0;
100 double _drateLast = 0.0;
101 };
102
103
104
106 : _curl( curl )
107 , _url(std::move( url ))
108 , _timeout( timeout )
109 , _timeoutReached( false )
110 , _fileSizeExceeded ( false )
111 , _expectedFileSize( expectedFileSize_r )
112 , report( _report )
113 {}
114
115 void ProgressData::updateStats( curl_off_t dltotal, curl_off_t dlnow )
116 {
117 time_t now = _timeNow = time(0);
118
119 // If called without args (0.0), recompute based on the last values seen
120 if ( dltotal && dltotal != _dnlTotal )
121 _dnlTotal = dltotal;
122
123 if ( dlnow && dlnow != _dnlNow )
124 {
125 _timeRcv = now;
126 _dnlNow = dlnow;
127 }
128
129 // init or reset if time jumps back
130 if ( !_timeStart || _timeStart > now )
131 _timeStart = _timeLast = _timeRcv = now;
132
133 // timeout condition
134 if ( _timeout )
135 _timeoutReached = ( (now - _timeRcv) > _timeout );
136
137 // check if the downloaded data is already bigger than what we expected
139
140 // percentage:
141 if ( _dnlTotal )
142 _dnlPercent = int( _dnlNow * 100 / _dnlTotal );
143
144 // download rates:
145 _drateTotal = double(_dnlNow) / std::max( int(now - _timeStart), 1 );
146
147 if ( _timeLast < now )
148 {
149 _drateLast = double(_dnlNow - _dnlLast) / int(now - _timeLast);
150 // start new period
151 _timeLast = now;
153 }
154 else if ( _timeStart == _timeLast )
156 }
157
159 {
160 if ( _fileSizeExceeded )
161 return 1;
162 if ( _timeoutReached )
163 return 1; // no-data timeout
164 if ( report && !(*report)->progress( _dnlPercent, _url, _drateTotal, _drateLast ) )
165 return 1; // user requested abort
166 return 0;
167 }
168
173 {
174 public:
176 const std::string & err_r,
177 const std::string & msg_r )
178 : media::MediaCurlException( url_r, err_r, msg_r )
179 {}
180 //~MediaCurlExceptionMayRetryInternaly() noexcept {}
181 };
182
183}
184
185
186using namespace internal;
187using namespace zypp::base;
188
189namespace zypp {
190
191 namespace media {
192
193Pathname MediaCurl::_cookieFile = "/var/lib/YaST2/cookies";
194
195// we use this define to unbloat code as this C setting option
196// and catching exception is done frequently.
198#define SET_OPTION(opt,val) do { \
199 ret = curl_easy_setopt ( curl, opt, val ); \
200 if ( ret != 0) { \
201 ZYPP_THROW(MediaCurlSetOptException(_origin.at(rData.mirror).url(), _curlError)); \
202 } \
203 } while ( false )
204
205#define SET_OPTION_OFFT(opt,val) SET_OPTION(opt,(curl_off_t)val)
206#define SET_OPTION_LONG(opt,val) SET_OPTION(opt,(long)val)
207#define SET_OPTION_VOID(opt,val) SET_OPTION(opt,(void*)val)
208
210 const Pathname & attach_point_hint_r )
211 : MediaNetworkCommonHandler( origin_r, attach_point_hint_r,
212 "/", // urlpath at attachpoint
213 true ), // does_download
215{
216 _multi = curl_multi_init();
217
218 _curlError[0] = '\0';
219
220 MIL << "MediaCurl::MediaCurl(" << origin_r.authority().url() << ", " << attach_point_hint_r << ")" << endl;
221
223
224 if( !attachPoint().empty())
225 {
226 PathInfo ainfo(attachPoint());
227 Pathname apath(attachPoint() + "XXXXXX");
228 char *atemp = ::strdup( apath.asString().c_str());
229 char *atest = NULL;
230 if( !ainfo.isDir() || !ainfo.userMayRWX() ||
231 atemp == NULL || (atest=::mkdtemp(atemp)) == NULL)
232 {
233 WAR << "attach point " << ainfo.path()
234 << " is not useable for " << origin_r.authority().url().getScheme() << endl;
235 setAttachPoint("", true);
236 }
237 else if( atest != NULL)
238 ::rmdir(atest);
239
240 if( atemp != NULL)
241 ::free(atemp);
242 }
243}
244
246{
247 try { release(); } catch(...) {}
248 if (_multi)
249 curl_multi_cleanup(_multi);
250}
251
252void MediaCurl::setCookieFile( const Pathname &fileName )
253{
254 _cookieFile = fileName;
255}
256
257void MediaCurl::setCurlError(const char* error)
258{
259 // FIXME(dmllr): Use strlcpy if available for better performance
260 strncpy(_curlError, error, sizeof(_curlError)-1);
261 _curlError[sizeof(_curlError)-1] = '\0';
262}
263
265
267{
268 curl_version_info_data *curl_info = NULL;
269 curl_info = curl_version_info(CURLVERSION_NOW);
270 // curl_info does not need any free (is static)
271 if (curl_info->protocols)
272 {
273 const char * const *proto = nullptr;
274 std::string scheme( url.getScheme());
275 bool found = false;
276 for(proto=curl_info->protocols; !found && *proto; ++proto)
277 {
278 if( scheme == std::string((const char *)*proto))
279 found = true;
280 }
281 if( !found)
282 {
283 std::string msg("Unsupported protocol '");
284 msg += scheme;
285 msg += "'";
287 }
288 }
289}
290
292{
293 CURL *curl = rData.curl;
294
295 // kill old settings
296 curl_easy_reset ( curl );
297
299 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, log_redirects_curl);
300 curl_easy_setopt(curl, CURLOPT_HEADERDATA, &_lastRedirect);
301 CURLcode ret = curl_easy_setopt( curl, CURLOPT_ERRORBUFFER, _curlError );
302 if ( ret != 0 ) {
303 ZYPP_THROW(MediaCurlSetOptException( _origin.at(rData.mirror).url(), "Error setting error buffer"));
304 }
305
306 SET_OPTION(CURLOPT_FAILONERROR, 1L);
307 SET_OPTION(CURLOPT_NOSIGNAL, 1L);
308
311 {
312 case 4: SET_OPTION(CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); break;
313 case 6: SET_OPTION(CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); break;
314 }
315
319 SET_OPTION(CURLOPT_CONNECTTIMEOUT, settings.connectTimeout());
320 // If a transfer timeout is set, also set CURLOPT_TIMEOUT to an upper limit
321 // just in case curl does not trigger its progress callback frequently
322 // enough.
323 if ( settings.timeout() )
324 {
325 SET_OPTION(CURLOPT_TIMEOUT, 3600L);
326 }
327
328 // follow any Location: header that the server sends as part of
329 // an HTTP header (#113275)
330 SET_OPTION(CURLOPT_FOLLOWLOCATION, 1L);
331 // 3 redirects seem to be too few in some cases (bnc #465532)
332 SET_OPTION(CURLOPT_MAXREDIRS, 6L);
333
334 if ( _origin.at(rData.mirror).url().getScheme() == "https" )
335 {
336 if ( :: internal::setCurlRedirProtocols ( curl ) != CURLE_OK ) {
338 }
339
340 if( settings.verifyPeerEnabled() ||
341 settings.verifyHostEnabled() )
342 {
343 SET_OPTION(CURLOPT_CAPATH, settings.certificateAuthoritiesPath().c_str());
344 }
345
346 if( ! settings.clientCertificatePath().empty() )
347 {
348 SET_OPTION(CURLOPT_SSLCERT, settings.clientCertificatePath().c_str());
349 }
350 if( ! settings.clientKeyPath().empty() )
351 {
352 SET_OPTION(CURLOPT_SSLKEY, settings.clientKeyPath().c_str());
353 }
354
355#ifdef CURLSSLOPT_ALLOW_BEAST
356 // see bnc#779177
357 ret = curl_easy_setopt( curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_ALLOW_BEAST );
358 if ( ret != 0 ) {
361 }
362#endif
363 SET_OPTION(CURLOPT_SSL_VERIFYPEER, settings.verifyPeerEnabled() ? 1L : 0L);
364 SET_OPTION(CURLOPT_SSL_VERIFYHOST, settings.verifyHostEnabled() ? 2L : 0L);
365 // bnc#903405 - POODLE: libzypp should only talk TLS
366 SET_OPTION(CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
367 }
368
369 SET_OPTION(CURLOPT_USERAGENT, settings.userAgentString().c_str() );
370
371 /* Fixes bsc#1174011 "auth=basic ignored in some cases"
372 * We should proactively add the password to the request if basic auth is configured
373 * and a password is available in the credentials but not in the URL.
374 *
375 * We will be a bit paranoid here and require that the URL has a user embedded, otherwise we go the default route
376 * and ask the server first about the auth method
377 */
378 if ( settings.authType() == "basic"
379 && settings.username().size()
380 && !settings.password().size() ) {
381
383 const auto cred = cm.getCred( _origin.at(rData.mirror).url() );
384 if ( cred && cred->valid() ) {
385 if ( !settings.username().size() )
386 settings.setUsername(cred->username());
387 settings.setPassword(cred->password());
388 }
389 }
390
391 /*---------------------------------------------------------------*
392 CURLOPT_USERPWD: [user name]:[password]
393
394 Url::username/password -> CURLOPT_USERPWD
395 If not provided, anonymous FTP identification
396 *---------------------------------------------------------------*/
397
398 if ( settings.userPassword().size() )
399 {
400 SET_OPTION(CURLOPT_USERPWD, settings.userPassword().c_str());
401 std::string use_auth = settings.authType();
402 if (use_auth.empty())
403 use_auth = "digest,basic"; // our default
404 long auth = CurlAuthData::auth_type_str2long(use_auth);
405 if( auth != CURLAUTH_NONE)
406 {
407 DBG << "Enabling HTTP authentication methods: " << use_auth
408 << " (CURLOPT_HTTPAUTH=" << auth << ")" << std::endl;
409 SET_OPTION(CURLOPT_HTTPAUTH, auth);
410 }
411 }
412
413 if ( settings.proxyEnabled() && ! settings.proxy().empty() )
414 {
415 DBG << "Proxy: '" << settings.proxy() << "'" << endl;
416 SET_OPTION(CURLOPT_PROXY, settings.proxy().c_str());
417 SET_OPTION(CURLOPT_PROXYAUTH, CURLAUTH_BASIC|CURLAUTH_DIGEST|CURLAUTH_NTLM );
418 /*---------------------------------------------------------------*
419 * CURLOPT_PROXYUSERPWD: [user name]:[password]
420 *
421 * Url::option(proxyuser and proxypassword) -> CURLOPT_PROXYUSERPWD
422 * If not provided, $HOME/.curlrc is evaluated
423 *---------------------------------------------------------------*/
424
425 std::string proxyuserpwd = settings.proxyUserPassword();
426
427 if ( proxyuserpwd.empty() )
428 {
429 CurlConfig curlconf;
430 CurlConfig::parseConfig(curlconf); // parse ~/.curlrc
431 if ( curlconf.proxyuserpwd.empty() )
432 DBG << "Proxy: ~/.curlrc does not contain the proxy-user option" << endl;
433 else
434 {
435 proxyuserpwd = curlconf.proxyuserpwd;
436 DBG << "Proxy: using proxy-user from ~/.curlrc" << endl;
437 }
438 }
439 else
440 {
441 DBG << "Proxy: using provided proxy-user '" << settings.proxyUsername() << "'" << endl;
442 }
443
444 if ( ! proxyuserpwd.empty() )
445 {
446 SET_OPTION(CURLOPT_PROXYUSERPWD, curlUnEscape( proxyuserpwd ).c_str());
447 }
448 }
449#if CURLVERSION_AT_LEAST(7,19,4)
450 else if ( settings.proxy() == EXPLICITLY_NO_PROXY )
451 {
452 // Explicitly disabled in URL (see fillSettingsFromUrl()).
453 // This should also prevent libcurl from looking into the environment.
454 DBG << "Proxy: explicitly NOPROXY" << endl;
455 SET_OPTION(CURLOPT_NOPROXY, "*");
456 }
457#endif
458 else
459 {
460 DBG << "Proxy: not explicitly set" << endl;
461 DBG << "Proxy: libcurl may look into the environment" << endl;
462 }
463
465 if ( settings.minDownloadSpeed() != 0 )
466 {
467 SET_OPTION(CURLOPT_LOW_SPEED_LIMIT, settings.minDownloadSpeed());
468 // default to 10 seconds at low speed
469 SET_OPTION(CURLOPT_LOW_SPEED_TIME, 60L);
470 }
471
472#if CURLVERSION_AT_LEAST(7,15,5)
473 if ( settings.maxDownloadSpeed() != 0 )
474 SET_OPTION_OFFT(CURLOPT_MAX_RECV_SPEED_LARGE, settings.maxDownloadSpeed());
475#endif
476
477 /*---------------------------------------------------------------*
478 *---------------------------------------------------------------*/
479
480 _currentCookieFile = _cookieFile.asString();
481 if ( ::geteuid() == 0 || PathInfo(_currentCookieFile).owner() == ::geteuid() )
483
484 const auto &cookieFileParam = _origin.at(rData.mirror).url().getQueryParam( "cookies" );
485 if ( !cookieFileParam.empty() && str::strToBool( cookieFileParam, true ) )
486 SET_OPTION(CURLOPT_COOKIEFILE, _currentCookieFile.c_str() );
487 else
488 MIL << "No cookies requested" << endl;
489 SET_OPTION(CURLOPT_COOKIEJAR, _currentCookieFile.c_str() );
490 SET_OPTION(CURLOPT_XFERINFOFUNCTION, &progressCallback );
491 SET_OPTION(CURLOPT_NOPROGRESS, 0L);
492
493#if CURLVERSION_AT_LEAST(7,18,0)
494 // bnc #306272
495 SET_OPTION(CURLOPT_PROXY_TRANSFER_MODE, 1L );
496#endif
497 // Append settings custom headers to curl.
498 // TransferSettings assert strings are trimmed (HTTP/2 RFC 9113)
499 if ( _customHeaders ) {
500 curl_slist_free_all(_customHeaders);
501 _customHeaders = 0L;
502 }
503 for ( const auto &header : settings.headers() ) {
504 _customHeaders = curl_slist_append(_customHeaders, header.c_str());
505 if ( !_customHeaders )
507 }
508 SET_OPTION(CURLOPT_HTTPHEADER, _customHeaders);
509}
510
512
514{
515 if ( _customHeaders ) {
516 curl_slist_free_all(_customHeaders);
517 _customHeaders = 0L;
518 }
519
520 // clear effective settings
522}
523
525
526void MediaCurl::releaseFrom( const std::string & ejectDev )
527{
528 disconnect();
529}
530
532
533void MediaCurl::getFileCopy( const OnMediaLocation & srcFile , const Pathname & target ) const
534{
535 // we need a non const pointer to work around the current API
536 auto that = const_cast<MediaCurl *>(this);
537 std::exception_ptr lastErr;
538 const auto &mirrOrder = mirrorOrder (srcFile);
539 for ( unsigned mirr : mirrOrder ) {
540 try {
541 return that->getFileCopyFromMirror ( mirr, srcFile, target );
542
543 } catch (MediaException & excpt_r) {
544 if ( !canTryNextMirror ( excpt_r ) )
545 ZYPP_RETHROW(excpt_r);
546 lastErr = ZYPP_FWD_CURRENT_EXCPT();
547 }
548 }
549 if ( lastErr ) {
550 ZYPP_RETHROW( lastErr );
551 }
552
553 // should not happen
554 ZYPP_THROW( MediaException("No usable mirror available.") );
555
556}
557
558void MediaCurl::getFileCopyFromMirror(const int mirror, const OnMediaLocation &srcFile, const Pathname &target)
559{
560 const auto &filename = srcFile.filename();
561
562 // Optional files will send no report until data are actually received (we know it exists).
563 OptionalDownloadProgressReport reportfilter( srcFile.optional() );
565
566 auto &myUrl = _origin[mirror];
567 auto &settings = myUrl.getConfig<TransferSettings>(MIRR_SETTINGS_KEY.data());
568
569 AutoDispose<CURL*> curl( curl_easy_init(), []( CURL *hdl ) { if ( hdl ) { curl_easy_cleanup(hdl); } } );
570
571 RequestData rData;
572 rData.mirror = mirror;
573 rData.curl = curl.value ();
574
575 if( !myUrl.url().isValid() )
576 ZYPP_THROW(MediaBadUrlException(myUrl.url()));
577
578 if( myUrl.url().getHost().empty() )
580
581 Url fileurl( getFileUrl(mirror, filename) );
582
583 bool firstAuth = true; // bsc#1210870: authenticate must not return stored credentials more than once.
584 unsigned internalTry = 0;
585 static constexpr unsigned maxInternalTry = 3;
586
587 do
588 {
589 try
590 {
591 Pathname dest = target.absolutename();
592 if( assert_dir( dest.dirname() ) )
593 {
594 DBG << "assert_dir " << dest.dirname() << " failed" << endl;
595 ZYPP_THROW( MediaSystemException(fileurl, "System error on " + dest.dirname().asString()) );
596 }
597
598 ManagedFile destNew { target.extend( ".new.zypp.XXXXXX" ) };
599 AutoFILE file;
600 {
601 AutoFREE<char> buf { ::strdup( (*destNew).c_str() ) };
602 if( ! buf )
603 {
604 ERR << "out of memory for temp file name" << endl;
605 ZYPP_THROW(MediaSystemException(fileurl, "out of memory for temp file name"));
606 }
607
608 AutoFD tmp_fd { ::mkostemp( buf, O_CLOEXEC ) };
609 if( tmp_fd == -1 )
610 {
611 ERR << "mkstemp failed for file '" << destNew << "'" << endl;
613 }
614 destNew = ManagedFile( (*buf), filesystem::unlink );
615
616 file = ::fdopen( tmp_fd, "we" );
617 if ( ! file )
618 {
619 ERR << "fopen failed for file '" << destNew << "'" << endl;
621 }
622 tmp_fd.resetDispose(); // don't close it here! ::fdopen moved ownership to file
623 }
624
625 DBG << "dest: " << dest << endl;
626 DBG << "temp: " << destNew << endl;
627
628 setupEasy( rData, settings );
629
630 // set IFMODSINCE time condition (no download if not modified)
631 if( PathInfo(target).isExist() )
632 {
633 curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
634 curl_easy_setopt(curl, CURLOPT_TIMEVALUE, (long)PathInfo(target).mtime());
635 }
636 else
637 {
638 curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
639 curl_easy_setopt(curl, CURLOPT_TIMEVALUE, 0L);
640 }
641
643 curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
644 curl_easy_setopt(curl, CURLOPT_TIMEVALUE, 0L);
645 };
646
647 DBG << srcFile.filename().asString() << endl;
648
649 DBG << "URL: " << fileurl.asString() << endl;
650 // Use URL without options and without username and passwd
651 // (some proxies dislike them in the URL).
652 // Curl seems to need the just scheme, hostname and a path;
653 // the rest was already passed as curl options (in attachTo).
654 Url curlUrl( clearQueryString(fileurl) );
655
656 //
657 // See also Bug #154197 and ftp url definition in RFC 1738:
658 // The url "ftp://user@host/foo/bar/file" contains a path,
659 // that is relative to the user's home.
660 // The url "ftp://user@host//foo/bar/file" (or also with
661 // encoded slash as %2f) "ftp://user@host/%2ffoo/bar/file"
662 // contains an absolute path.
663 //
664 _lastRedirect.clear();
665 std::string urlBuffer( curlUrl.asString());
666 CURLcode ret = curl_easy_setopt( curl, CURLOPT_URL,
667 urlBuffer.c_str() );
668 if ( ret != 0 ) {
670 }
671
672 ret = curl_easy_setopt( curl, CURLOPT_WRITEDATA, file.value() );
673 if ( ret != 0 ) {
675 }
676
677 // Set callback and perform.
678 internal::ProgressData progressData( curl, settings.timeout(), fileurl, srcFile.downloadSize(), &report );
679 report->start(fileurl, dest);
680
681 if ( curl_easy_setopt( curl, CURLOPT_PROGRESSDATA, &progressData ) != 0 ) {
682 WAR << "Can't set CURLOPT_PROGRESSDATA: " << _curlError << endl;;
683 }
684
685 ret = executeCurl( rData );
686 #if CURLVERSION_AT_LEAST(7,19,4)
687 // bnc#692260: If the client sends a request with an If-Modified-Since header
688 // with a future date for the server, the server may respond 200 sending a
689 // zero size file.
690 // curl-7.19.4 introduces CURLINFO_CONDITION_UNMET to check this condition.
691 if ( ftell(file) == 0 && ret == 0 )
692 {
693 long httpReturnCode = 33;
694 if ( curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &httpReturnCode ) == CURLE_OK && httpReturnCode == 200 )
695 {
696 long conditionUnmet = 33;
697 if ( curl_easy_getinfo( curl, CURLINFO_CONDITION_UNMET, &conditionUnmet ) == CURLE_OK && conditionUnmet )
698 {
699 WAR << "TIMECONDITION unmet - retry without." << endl;
700 curl_easy_setopt( curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
701 curl_easy_setopt( curl, CURLOPT_TIMEVALUE, 0L);
702 ret = executeCurl( rData );
703 }
704 }
705 }
706 #endif
707
708 if ( curl_easy_setopt( curl, CURLOPT_PROGRESSDATA, NULL ) != 0 ) {
709 WAR << "Can't unset CURLOPT_PROGRESSDATA: " << _curlError << endl;;
710 }
711
712 if ( ret != 0 ) {
713 ERR << "curl error: " << ret << ": " << _curlError
714 << ", temp file size " << ftell(file)
715 << " bytes." << endl;
716
717 // the timeout is determined by the progress data object
718 // which holds whether the timeout was reached or not,
719 // otherwise it would be a user cancel
720
721 if ( progressData.fileSizeExceeded() )
723
724 evaluateCurlCode( rData, srcFile.filename(), ret, progressData.timeoutReached() );
725 }
726
727 long httpReturnCode = 0;
728 CURLcode infoRet = curl_easy_getinfo(curl,
729 CURLINFO_RESPONSE_CODE,
730 &httpReturnCode);
731 bool modified = true;
732 if (infoRet == CURLE_OK)
733 {
734 DBG << "HTTP response: " + str::numstring(httpReturnCode);
735 if ( httpReturnCode == 304
736 || ( httpReturnCode == 213 && (myUrl.url().getScheme() == "ftp" || myUrl.url().getScheme() == "tftp") ) ) // not modified
737 {
738 DBG << " Not modified.";
739 modified = false;
740 }
741 DBG << endl;
742 }
743 else
744 {
745 WAR << "Could not get the response code." << endl;
746 }
747
748 if (modified || infoRet != CURLE_OK)
749 {
750 // apply umask
751 if ( ::fchmod( ::fileno(file), filesystem::applyUmaskTo( 0644 ) ) )
752 {
753 ERR << "Failed to chmod file " << destNew << endl;
754 }
755
756 file.resetDispose(); // we're going to close it manually here
757 if ( ::fclose( file ) )
758 {
759 ERR << "Fclose failed for file '" << destNew << "'" << endl;
761 }
762
763 // move the temp file into dest
764 if ( rename( destNew, dest ) != 0 ) {
765 ERR << "Rename failed" << endl;
767 }
768 destNew.resetDispose(); // no more need to unlink it
769 }
770
771 DBG << "done: " << PathInfo(dest) << endl;
772 break; // success!
773 }
774 // retry with proper authentication data
775 catch (MediaUnauthorizedException & ex_r)
776 {
777 if ( authenticate( myUrl.url(), settings, ex_r.hint(), firstAuth) ) {
778 firstAuth = false; // must not return stored credentials again
779 continue; // retry
780 }
781
783 ZYPP_RETHROW(ex_r);
784 }
785 // unexpected exception
786 catch (MediaException & excpt_r)
787 {
788 if ( typeid(excpt_r) == typeid( MediaCurlExceptionMayRetryInternaly ) ) {
789 ++internalTry;
790 if ( internalTry < maxInternalTry ) {
791 // just report (NO_ERROR); no interactive request to the user
792 report->problem(fileurl, media::DownloadProgressReport::NO_ERROR, excpt_r.asUserHistory()+_("Will try again..."));
793 continue; // retry
794 }
795 excpt_r.addHistory( str::Format(_("Giving up after %1% attempts.")) % maxInternalTry );
796 }
797
799 if( typeid(excpt_r) == typeid( media::MediaFileNotFoundException ) ||
800 typeid(excpt_r) == typeid( media::MediaNotAFileException ) )
801 {
803 }
804 report->finish(fileurl, reason, excpt_r.asUserHistory());
805 ZYPP_RETHROW(excpt_r);
806 }
807 } while ( true );
808
809 report->finish(fileurl, zypp::media::DownloadProgressReport::NO_ERROR, "");
810}
811
813
814bool MediaCurl::getDoesFileExist( const Pathname & filename ) const
815{
816 // we need a non const pointer to work around the current API
817 auto that = const_cast<MediaCurl *>(this);
818
819 std::exception_ptr lastErr;
820 for ( int i : mirrorOrder( OnMediaLocation(filename).setMirrorsAllowed(false) )) {
821 try {
822 return that->doGetDoesFileExist( i, filename );
823
824 } catch (MediaException & excpt_r) {
825 if ( !canTryNextMirror ( excpt_r ) )
826 ZYPP_RETHROW(excpt_r);
827 lastErr = ZYPP_FWD_CURRENT_EXCPT();
828 }
829 }
830 if ( lastErr ) {
831 try {
832 ZYPP_RETHROW( lastErr );
833 } catch ( const MediaFileNotFoundException &e ) {
834 // on file not found we return false
835 ZYPP_CAUGHT(e);
836 return false;
837 }
838 }
839 return false;
840}
841
843
845 const Pathname &filename,
846 CURLcode code,
847 bool timeout_reached) const
848{
849 if ( code != 0 )
850 {
851 const auto &baseMirr = _origin[rData.mirror];
852 Url url;
853 if (filename.empty())
854 url = baseMirr.url();
855 else
856 url = getFileUrl(rData.mirror, filename);
857
858 std::string err;
859 {
860 switch ( code )
861 {
862 case CURLE_UNSUPPORTED_PROTOCOL:
863 err = " Unsupported protocol";
864 if ( !_lastRedirect.empty() )
865 {
866 err += " or redirect (";
867 err += _lastRedirect;
868 err += ")";
869 }
870 break;
871 case CURLE_URL_MALFORMAT:
872 case CURLE_URL_MALFORMAT_USER:
873 err = " Bad URL";
874 break;
875 case CURLE_LOGIN_DENIED:
877 MediaUnauthorizedException(url, "Login failed.", _curlError, ""));
878 break;
879 case CURLE_HTTP_RETURNED_ERROR:
880 {
881 long httpReturnCode = 0;
882 CURLcode infoRet = curl_easy_getinfo( rData.curl,
883 CURLINFO_RESPONSE_CODE,
884 &httpReturnCode );
885 if ( infoRet == CURLE_OK )
886 {
887 std::string msg = "HTTP response: " + str::numstring( httpReturnCode );
888 switch ( httpReturnCode )
889 {
890 case 401:
891 {
892 std::string auth_hint = getAuthHint( rData.curl );
893
894 DBG << msg << " Login failed (URL: " << url.asString() << ")" << std::endl;
895 DBG << "MediaUnauthorizedException auth hint: '" << auth_hint << "'" << std::endl;
896
898 url, "Login failed.", _curlError, auth_hint
899 ));
900 }
901
902 case 502: // bad gateway (bnc #1070851)
903 case 503: // service temporarily unavailable (bnc #462545)
905 case 504: // gateway timeout
907 case 403:
908 {
909 std::string msg403;
910 if ( url.getHost().find(".suse.com") != std::string::npos )
911 msg403 = _("Visit the SUSE Customer Center to check whether your registration is valid and has not expired.");
912 else if (url.asString().find("novell.com") != std::string::npos)
913 msg403 = _("Visit the Novell Customer Center to check whether your registration is valid and has not expired.");
915 }
916 case 404:
917 case 410:
918 ZYPP_THROW(MediaFileNotFoundException(baseMirr.url(), filename));
919 }
920
921 DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
923 }
924 else
925 {
926 std::string msg = "Unable to retrieve HTTP response:";
927 DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
929 }
930 }
931 break;
932 case CURLE_FTP_COULDNT_RETR_FILE:
933#if CURLVERSION_AT_LEAST(7,16,0)
934 case CURLE_REMOTE_FILE_NOT_FOUND:
935#endif
936 case CURLE_FTP_ACCESS_DENIED:
937 case CURLE_TFTP_NOTFOUND:
938 err = "File not found";
939 ZYPP_THROW(MediaFileNotFoundException(baseMirr.url(), filename));
940 break;
941 case CURLE_BAD_PASSWORD_ENTERED:
942 case CURLE_FTP_USER_PASSWORD_INCORRECT:
943 err = "Login failed";
944 break;
945 case CURLE_COULDNT_RESOLVE_PROXY:
946 case CURLE_COULDNT_RESOLVE_HOST:
947 case CURLE_COULDNT_CONNECT:
948 case CURLE_FTP_CANT_GET_HOST:
949 err = "Connection failed";
950 break;
951 case CURLE_WRITE_ERROR:
952 err = "Write error";
953 break;
954 case CURLE_PARTIAL_FILE:
955 case CURLE_OPERATION_TIMEDOUT:
956 timeout_reached = true; // fall though to TimeoutException
957 // fall though...
958 case CURLE_ABORTED_BY_CALLBACK:
959 if( timeout_reached )
960 {
961 err = "Timeout reached";
963 }
964 else
965 {
966 err = "User abort";
967 }
968 break;
969
970 default:
971 err = "Curl error " + str::numstring( code );
972 break;
973 }
974
975 // uhm, no 0 code but unknown curl exception
977 }
978 }
979 else
980 {
981 // actually the code is 0, nothing happened
982 }
983}
984
986
987bool MediaCurl::doGetDoesFileExist( const int mirror, const Pathname & filename )
988{
989 DBG << filename.asString() << endl;
990
991 AutoDispose<CURL*> curl( curl_easy_init(), []( CURL *hdl ) { if ( hdl ) { curl_easy_cleanup(hdl); } } );
992 RequestData rData;
993 rData.mirror = mirror;
994 rData.curl = curl.value ();
995
996 auto &myUrl = _origin[mirror];
997
998 if( !myUrl.url().isValid() )
999 ZYPP_THROW(MediaBadUrlException(myUrl.url()));
1000
1001 if( myUrl.url().getHost().empty() )
1003
1004 Url url(getFileUrl(mirror, filename));
1005
1006 DBG << "URL: " << url.asString() << endl;
1007 // Use URL without options and without username and passwd
1008 // (some proxies dislike them in the URL).
1009 // Curl seems to need the just scheme, hostname and a path;
1010 // the rest was already passed as curl options (in attachTo).
1011 Url curlUrl( clearQueryString(url) );
1012
1013 // See also Bug #154197 and ftp url definition in RFC 1738:
1014 // The url "ftp://user@host/foo/bar/file" contains a path,
1015 // that is relative to the user's home.
1016 // The url "ftp://user@host//foo/bar/file" (or also with
1017 // encoded slash as %2f) "ftp://user@host/%2ffoo/bar/file"
1018 // contains an absolute path.
1019 //
1020 _lastRedirect.clear();
1021 std::string urlBuffer( curlUrl.asString());
1022
1023 CURLcode ok;
1024 bool canRetry = true;
1025 bool firstAuth = true;
1026 auto &settings = myUrl.getConfig<TransferSettings>( MIRR_SETTINGS_KEY.data() );
1027
1028 while ( canRetry ) {
1029 canRetry = false;
1030 setupEasy( rData, settings );
1031
1032 CURLcode ret = curl_easy_setopt( curl, CURLOPT_URL,
1033 urlBuffer.c_str() );
1034 if ( ret != 0 ) {
1036 }
1037
1038 AutoFILE file { ::fopen( "/dev/null", "w" ) };
1039 if ( !file ) {
1040 ERR << "fopen failed for /dev/null" << endl;
1041 ZYPP_THROW(MediaWriteException("/dev/null"));
1042 }
1043
1044 ret = curl_easy_setopt( curl, CURLOPT_WRITEDATA, (*file) );
1045 if ( ret != 0 ) {
1047 }
1048
1049 // If no head requests allowed (?head_requests=no):
1050 // Instead of returning no data with NOBODY, we return
1051 // little data, that works with broken servers, and
1052 // works for ftp as well, because retrieving only headers
1053 // ftp will return always OK code ?
1054 // See http://curl.haxx.se/docs/knownbugs.html #58
1055 const bool doHeadRequest = (myUrl.url().getScheme() == "http" || myUrl.url().getScheme() == "https") && settings.headRequestsAllowed();
1056 if ( doHeadRequest ) {
1057 curl_easy_setopt( curl, CURLOPT_NOBODY, 1L );
1058 } else {
1059 curl_easy_setopt( curl, CURLOPT_RANGE, "0-1" );
1060 }
1061
1062 try {
1063 ok = const_cast<MediaCurl *>(this)->executeCurl( rData );
1064 MIL << "perform code: " << ok << " [ " << curl_easy_strerror(ok) << " ]" << endl;
1065
1066 // as we are not having user interaction, the user can't cancel
1067 // the file existence checking, a callback or timeout return code
1068 // will be always a timeout.
1069 evaluateCurlCode( rData, filename, ok, true /* timeout */);
1070 }
1071 catch ( const MediaFileNotFoundException &e ) {
1072 // if the file did not exist then we can return false
1073 return false;
1074 }
1075 catch ( const MediaUnauthorizedException &e ) {
1076 if ( authenticate( myUrl.url(), settings, e.hint(), firstAuth ) ) {
1077 firstAuth = false;
1078 canRetry = true;
1079 continue;
1080 }
1081 }
1082
1083 // exists
1084 return ( ok == CURLE_OK );
1085 }
1086
1087 return false;
1088}
1089
1091//
1092int MediaCurl::aliveCallback( void *clientp, curl_off_t /*dltotal*/, curl_off_t dlnow, curl_off_t /*ultotal*/, curl_off_t /*ulnow*/ )
1093{
1094 internal::ProgressData *pdata = reinterpret_cast<internal::ProgressData *>( clientp );
1095 if( pdata )
1096 {
1097 // Do not propagate dltotal in alive callbacks. MultiCurl uses this to
1098 // prevent a percentage raise while downloading a metalink file. Download
1099 // activity however is indicated by propagating the download rate (via dlnow).
1100 pdata->updateStats( 0.0, dlnow );
1101 return pdata->reportProgress();
1102 }
1103 return 0;
1104}
1105
1106int MediaCurl::progressCallback( void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow )
1107{
1108 internal::ProgressData *pdata = reinterpret_cast<internal::ProgressData *>( clientp );
1109 if( pdata )
1110 {
1111 // work around curl bug that gives us old data
1112 long httpReturnCode = 0;
1113 if ( curl_easy_getinfo( pdata->curl(), CURLINFO_RESPONSE_CODE, &httpReturnCode ) != CURLE_OK || httpReturnCode == 0 ) {
1114 return aliveCallback( clientp, dltotal, dlnow, ultotal, ulnow );
1115 }
1116
1117 // bsc#1245220 If we get some answer outside the HTTP 200 range, we might need to adapt the
1118 // expected filesize. Otherwise the payload of the answer will trigger "filesize exceeded" errors
1119 // in some cases.
1120 const auto &scheme = pdata->url().getScheme();
1121 if ( ( scheme == "http" || scheme == "https" ) && ( httpReturnCode < 200 || httpReturnCode > 299 ) ) {
1122 curl_off_t cl = 0;
1123 curl_easy_getinfo(pdata->curl(), CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &cl);
1124 if ( cl > 0 ) {
1125 const auto &expSize = pdata->expectedFileSize();
1126 if ( expSize && pdata->expectedFileSize() < cl ) {
1127 MIL << "Content length for HTTP message: " << httpReturnCode << " is bigger than our expected filesize, adjusting" << std::endl;
1128 resetExpectedFileSize ( pdata, cl );
1129 } else {
1130 MIL << "Content length for HTTP message: " << httpReturnCode << " is smaller or equal to our expected filesize, ignoring" << std::endl;
1131 }
1132 } else {
1133 MIL << "Content length for HTTP message: " << httpReturnCode << " is not known, setting it to max 2MB!" << std::endl;
1135 }
1136 }
1137
1138 pdata->updateStats( dltotal, dlnow );
1139 return pdata->reportProgress();
1140 }
1141 return 0;
1142}
1143
1145{
1146 internal::ProgressData *pdata = reinterpret_cast<internal::ProgressData *>(clientp);
1147 return pdata ? pdata->curl() : 0;
1148}
1149
1151
1152std::string MediaCurl::getAuthHint( CURL *curl ) const
1153{
1154 long auth_info = CURLAUTH_NONE;
1155
1156 CURLcode infoRet =
1157 curl_easy_getinfo(curl, CURLINFO_HTTPAUTH_AVAIL, &auth_info);
1158
1159 if(infoRet == CURLE_OK)
1160 {
1161 return CurlAuthData::auth_type_long2str(auth_info);
1162 }
1163
1164 return "";
1165}
1166
1171void MediaCurl::resetExpectedFileSize(void *clientp, const ByteCount &expectedFileSize)
1172{
1173 internal::ProgressData *data = reinterpret_cast<internal::ProgressData *>(clientp);
1174 if ( data ) {
1175 data->expectedFileSize( expectedFileSize );
1176 }
1177}
1178
1185{
1186 CURL *curl = rData.curl;
1187 const auto &baseUrl = _origin.at(rData.mirror);
1188
1189 if (!_multi)
1190 ZYPP_THROW(MediaCurlInitException(baseUrl.url()));
1191
1192 internal::CurlPollHelper _curlHelper(*this);
1193
1194 // add the easy handle to the multi instance
1195 if ( curl_multi_add_handle( _multi, curl ) != CURLM_OK )
1196 ZYPP_THROW(MediaCurlException( baseUrl.url(), "curl_multi_add_handle", "unknown error"));
1197
1198 // make sure the handle is cleanly removed from the multi handle
1199 OnScopeExit autoRemove([&](){ curl_multi_remove_handle( _multi, curl ); });
1200
1201 // kickstart curl, this will cause libcurl to go over the added handles and register sockets and timeouts
1202 CURLMcode mcode = _curlHelper.handleTimout();
1203 if (mcode != CURLM_OK)
1204 ZYPP_THROW(MediaCurlException( baseUrl.url(), "curl_multi_socket_action", "unknown error"));
1205
1206 bool canContinue = true;
1207 while ( canContinue ) {
1208
1209 CURLMsg *msg = nullptr;
1210 int nqueue = 0;
1211 while ((msg = curl_multi_info_read( _multi, &nqueue)) != 0) {
1212 if ( msg->msg != CURLMSG_DONE ) continue;
1213 if ( msg->easy_handle != curl ) continue;
1214
1215 return msg->data.result;
1216 }
1217
1218 // copy watched sockets in case curl changes the vector as we go over the events later
1219 std::vector<GPollFD> requestedFds = _curlHelper.socks;
1220
1221 int r = zypp_detail::zypp_poll( requestedFds, _curlHelper.timeout_ms.value_or( -1 ) );
1222 if ( r == -1 )
1223 ZYPP_THROW( MediaCurlException(baseUrl.url(), "zypp_poll() failed", "unknown error") );
1224
1225 // run curl
1226 if ( r == 0 ) {
1227 CURLMcode mcode = _curlHelper.handleTimout();
1228 if (mcode != CURLM_OK)
1229 ZYPP_THROW(MediaCurlException(baseUrl.url(), "curl_multi_socket_action", "unknown error"));
1230 } else {
1231 CURLMcode mcode = _curlHelper.handleSocketActions( requestedFds );
1232 if (mcode != CURLM_OK)
1233 ZYPP_THROW(MediaCurlException(baseUrl.url(), "curl_multi_socket_action", "unknown error"));
1234 }
1235 }
1236 return CURLE_OK;
1237}
1238
1239
1240 } // namespace media
1241} // namespace zypp
1242//
#define SET_OPTION_OFFT(opt, val)
Definition MediaCurl.cc:205
#define SET_OPTION(opt, val)
Definition MediaCurl.cc:198
Attempt to work around certain issues by autoretry in MediaCurl::getFileCopy E.g.
Definition MediaCurl.cc:173
MediaCurlExceptionMayRetryInternaly(const Url &url_r, const std::string &err_r, const std::string &msg_r)
Definition MediaCurl.cc:175
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition AutoDispose.h:95
reference value() const
Reference to the Tp object.
void resetDispose()
Set no dispose function.
Store and operate with byte count.
Definition ByteCount.h:32
static const Unit MB
1000^2 Byte
Definition ByteCount.h:61
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition Exception.cc:140
void addHistory(const std::string &msg_r)
Add some message text to the history.
Definition Exception.cc:189
Manages a data source characterized by an authoritative URL and a list of mirror URLs.
const OriginEndpoint & authority() const
Describes a resource file located on a medium.
bool optional() const
Whether this is an optional resource.
const ByteCount & downloadSize() const
The size of the resource on the server.
const Pathname & filename() const
The path to the resource on the medium.
const zypp::Url & url() const
ProgressData()
Ctor no range [0,0](0).
Url manipulation class.
Definition Url.h:93
std::string getScheme() const
Returns the scheme name of the URL.
Definition Url.cc:551
std::string asString() const
Returns a default string representation of the Url object.
Definition Url.cc:515
static ZConfig & instance()
Singleton ctor.
Definition ZConfig.cc:940
Wrapper class for stat/lstat.
Definition PathInfo.h:226
const Pathname & path() const
Return current Pathname.
Definition PathInfo.h:251
Pathname dirname() const
Return all but the last component od this path.
Definition Pathname.h:126
const char * c_str() const
String representation.
Definition Pathname.h:112
const std::string & asString() const
String representation.
Definition Pathname.h:93
bool empty() const
Test for an empty path.
Definition Pathname.h:116
AuthData_Ptr getCred(const Url &url)
Get credentials for the specified url.
static std::string auth_type_long2str(long auth_type)
Converts a long of ORed CURLAUTH_* identifiers into a string of comma separated list of authenticatio...
static long auth_type_str2long(std::string &auth_type_str)
Converts a string of comma separated list of authetication type names into a long of ORed CURLAUTH_* ...
MediaCurlException(const Url &url_r, std::string err_r, std::string msg_r)
bool doGetDoesFileExist(const int mirror, const Pathname &filename)
Definition MediaCurl.cc:987
void checkProtocol(const Url &url) const override
check the url is supported by the curl library
Definition MediaCurl.cc:266
static void setCookieFile(const Pathname &)
Definition MediaCurl.cc:252
bool getDoesFileExist(const Pathname &filename) const override
Repeatedly calls doGetDoesFileExist() until it successfully returns, fails unexpectedly,...
Definition MediaCurl.cc:814
static void resetExpectedFileSize(void *clientp, const ByteCount &expectedFileSize)
MediaMultiCurl needs to reset the expected filesize in case a metalink file is downloaded otherwise t...
std::string _currentCookieFile
Definition MediaCurl.h:125
static Pathname _cookieFile
Definition MediaCurl.h:126
std::string getAuthHint(CURL *curl) const
Return a comma separated list of available authentication methods supported by server.
void getFileCopyFromMirror(const int mirror, const OnMediaLocation &srcFile, const Pathname &target)
Definition MediaCurl.cc:558
static int progressCallback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
Callback reporting download progress.
std::string _lastRedirect
to log/report redirections
Definition MediaCurl.h:129
char _curlError[CURL_ERROR_SIZE]
Definition MediaCurl.h:127
void evaluateCurlCode(RequestData &rData, const zypp::Pathname &fileName, CURLcode code, bool timeout) const
Evaluates a curl return code and throws the right MediaException filename Filename being downloaded c...
Definition MediaCurl.cc:844
CURLcode executeCurl(RequestData &rData)
MediaCurl(const MirroredOrigin &origin_r, const Pathname &attach_point_hint_r)
Definition MediaCurl.cc:209
void setCurlError(const char *error)
Definition MediaCurl.cc:257
static CURL * progressCallback_getcurl(void *clientp)
void releaseFrom(const std::string &ejectDev) override
Call concrete handler to release the media.
Definition MediaCurl.cc:526
static int aliveCallback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
Callback sending just an alive trigger to the UI, without stats (e.g.
void disconnectFrom() override
Definition MediaCurl.cc:513
void setupEasy(RequestData &rData, TransferSettings &settings)
initializes the curl easy handle with the data from the url
Definition MediaCurl.cc:291
curl_slist * _customHeaders
Definition MediaCurl.h:130
void getFileCopy(const OnMediaLocation &srcFile, const Pathname &target) const override
Definition MediaCurl.cc:533
Just inherits Exception to separate media exceptions.
MirroredOrigin _origin
Contains the authority URL and mirrors.
Url url() const
Primary Url used.
void disconnect()
Use concrete handler to isconnect media.
void release(const std::string &ejectDev="")
Use concrete handler to release the media.
void setAttachPoint(const Pathname &path, bool temp)
Set a new attach point.
Pathname attachPoint() const
Return the currently used attach point.
bool authenticate(const Url &url, TransferSettings &settings, const std::string &availAuthTypes, bool firstTry)
static bool canTryNextMirror(const Excpt &excpt_r)
std::vector< unsigned > mirrorOrder(const OnMediaLocation &loc) const
Url getFileUrl(int mirrorIdx, const Pathname &filename) const
concatenate the attach url and the filename to a complete download url
MediaNetworkCommonHandler(const MirroredOrigin &origin_r, const Pathname &attach_point_r, const Pathname &urlpath_below_attachpoint_r, const bool does_download_r)
static constexpr std::string_view MIRR_SETTINGS_KEY
const std::string & hint() const
comma separated list of available authentication types
Holds transfer setting.
const std::string & password() const
auth password
long maxDownloadSpeed() const
Maximum download speed (bytes per second)
long connectTimeout() const
connection timeout
const std::string & authType() const
get the allowed authentication types
long timeout() const
transfer timeout
void setUsername(const std::string &val_r)
sets the auth username
const Pathname & clientCertificatePath() const
SSL client certificate file.
std::string userPassword() const
returns the user and password as a user:pass string
long minDownloadSpeed() const
Minimum download speed (bytes per second) until the connection is dropped.
const Headers & headers() const
returns a list of all added headers (trimmed)
const std::string & proxy() const
proxy host
const Pathname & clientKeyPath() const
SSL client key file.
std::string proxyUserPassword() const
returns the proxy user and password as a user:pass string
bool verifyHostEnabled() const
Whether to verify host for ssl.
const std::string & userAgentString() const
user agent string (trimmed)
void setPassword(const std::string &val_r)
sets the auth password
bool proxyEnabled() const
proxy is enabled
const std::string & username() const
auth username
const std::string & proxyUsername() const
proxy auth username
const Pathname & certificateAuthoritiesPath() const
SSL certificate authorities path ( default: /etc/ssl/certs )
bool verifyPeerEnabled() const
Whether to verify peer for ssl.
#define EXPLICITLY_NO_PROXY
size_t log_redirects_curl(char *ptr, size_t size, size_t nmemb, void *userdata)
void globalInitCurlOnce()
Definition curlhelper.cc:64
std::string curlUnEscape(const std::string &text_r)
void setupZYPP_MEDIA_CURL_DEBUG(CURL *curl)
Setup CURLOPT_VERBOSE and CURLOPT_DEBUGFUNCTION according to env::ZYPP_MEDIA_CURL_DEBUG.
CURLcode setCurlRedirProtocols(CURL *curl)
Definition Arch.h:364
int ZYPP_MEDIA_CURL_IPRESOLVE()
4/6 to force IPv4/v6
Definition curlhelper.cc:45
mode_t applyUmaskTo(mode_t mode_r)
Modify mode_r according to the current umask ( mode_r & ~getUmask() ).
Definition PathInfo.h:805
int assert_file_mode(const Pathname &path, unsigned mode)
Like assert_file but enforce mode even if the file already exists.
Definition PathInfo.cc:1210
int unlink(const Pathname &path)
Like 'unlink'.
Definition PathInfo.cc:705
std::string numstring(char n, int w=0)
Definition String.h:290
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
Definition String.h:500
int zypp_poll(std::vector< GPollFD > &fds, int timeout)
Small wrapper around g_poll that additionally listens to the shutdown FD returned by ZYpp::shutdownSi...
Definition ZYppImpl.cc:313
Easy-to use interface to the ZYPP dependency resolver.
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition ManagedFile.h:27
AutoDispose< void > OnScopeExit
CURLMcode handleSocketActions(const std::vector< GPollFD > &actionsFds, int first=0)
std::vector< GPollFD > socks
std::optional< long > timeout_ms
Bottleneck filtering all DownloadProgressReport issued from Media[Muli]Curl.
ByteCount _expectedFileSize
Definition MediaCurl.cc:85
curl_off_t _dnlNow
Bytes downloaded now.
Definition MediaCurl.cc:95
int _dnlPercent
Percent completed or 0 if _dnlTotal is unknown.
Definition MediaCurl.cc:97
time_t _timeRcv
Start of no-data timeout.
Definition MediaCurl.cc:90
ByteCount expectedFileSize() const
Definition MediaCurl.cc:70
time_t _timeLast
Start last period(~1sec)
Definition MediaCurl.cc:89
int reportProgress() const
Definition MediaCurl.cc:158
double _drateLast
Download rate in last period.
Definition MediaCurl.cc:100
bool timeoutReached() const
Definition MediaCurl.cc:64
void expectedFileSize(ByteCount newval_r)
Definition MediaCurl.cc:73
zypp::Url url() const
Definition MediaCurl.cc:76
curl_off_t _dnlLast
Bytes downloaded at period start.
Definition MediaCurl.cc:94
bool fileSizeExceeded() const
Definition MediaCurl.cc:67
void updateStats(curl_off_t dltotal=0.0, curl_off_t dlnow=0.0)
Definition MediaCurl.cc:115
double _drateTotal
Download rate so far.
Definition MediaCurl.cc:99
zypp::callback::SendReport< zypp::media::DownloadProgressReport > * report
Definition MediaCurl.cc:86
curl_off_t _dnlTotal
Bytes to download or 0 if unknown.
Definition MediaCurl.cc:93
time_t _timeStart
Start total stats.
Definition MediaCurl.cc:88
ProgressData(CURL *curl, time_t timeout=0, zypp::Url url=zypp::Url(), zypp::ByteCount expectedFileSize_r=0, zypp::callback::SendReport< zypp::media::DownloadProgressReport > *_report=nullptr)
Definition MediaCurl.cc:105
AutoDispose<int> calling close
AutoDispose<FILE*> calling fclose
Structure holding values of curlrc options.
Definition curlconfig.h:27
std::string proxyuserpwd
Definition curlconfig.h:49
static int parseConfig(CurlConfig &config, const std::string &filename="")
Parse a curlrc file and store the result in the config structure.
Definition curlconfig.cc:24
Convenient building of std::string with boost::format.
Definition String.h:254
#define zypp_defer
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition Exception.h:479
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:475
#define ZYPP_FWD_CURRENT_EXCPT()
Drops a logline and returns the current Exception as a std::exception_ptr.
Definition Exception.h:471
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
#define _(MSG)
Definition Gettext.h:39
#define DBG
Definition Logger.h:99
#define MIL
Definition Logger.h:100
#define ERR
Definition Logger.h:102
#define WAR
Definition Logger.h:101
Interface to gettext.