libzypp 17.37.10

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