libzypp 17.35.1
MediaCurl.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
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>
33#include <zypp/Target.h>
34#include <zypp/ZYppFactory.h>
35#include <zypp/ZConfig.h>
36#include <zypp/zypp_detail/ZYppImpl.h> // for zypp_poll
37
38#include <cstdlib>
39#include <sys/types.h>
40#include <sys/stat.h>
41#include <sys/mount.h>
42#include <dirent.h>
43#include <unistd.h>
44#include <glib.h>
45
46using std::endl;
47
48namespace internal {
49 using namespace zypp;
53 struct OptionalDownloadProgressReport : public callback::ReceiveReport<media::DownloadProgressReport>
54 {
55 using TimePoint = std::chrono::steady_clock::time_point;
56
57 OptionalDownloadProgressReport( bool isOptional=false )
58 : _oldRec { Distributor::instance().getReceiver() }
59 , _isOptional { isOptional }
60 { connect(); }
61
66
68 if (_oldRec)
69 Distributor::instance().setReceiver(*_oldRec);
70 else
71 Distributor::instance().noReceiver();
72 }
73
74 void reportbegin() override
75 { if ( _oldRec ) _oldRec->reportbegin(); }
76
77 void reportend() override
78 { if ( _oldRec ) _oldRec->reportend(); }
79
80 void report( const UserData & userData_r = UserData() ) override
81 { if ( _oldRec ) _oldRec->report( userData_r ); }
82
83
84 void start( const Url & file_r, Pathname localfile_r ) override
85 {
86 if ( not _oldRec ) return;
87 if ( _isOptional ) {
88 // delay start until first data are received.
90 _startLocalfile = std::move(localfile_r);
91 return;
92 }
94 }
95
96 bool progress( int value_r, const Url & file_r, double dbps_avg_r = -1, double dbps_current_r = -1 ) override
97 {
98 if ( not _oldRec ) return true;
99 if ( notStarted() ) {
100 if ( not ( value_r || dbps_avg_r || dbps_current_r ) )
101 return true;
102 sendStart();
103 }
104
105 //static constexpr std::chrono::milliseconds minfequency { 1000 }; only needed if we'd avoid sending reports without change
106 static constexpr std::chrono::milliseconds maxfequency { 100 };
107 TimePoint now { TimePoint::clock::now() };
108 TimePoint::duration elapsed { now - _lastProgressSent };
109 if ( elapsed < maxfequency )
110 return true; // continue
111 _lastProgressSent = now;
113 }
114
115 Action problem( const Url & file_r, Error error_r, const std::string & description_r ) override
116 {
117 if ( not _oldRec || notStarted() ) return ABORT;
119 }
120
121 void finish( const Url & file_r, Error error_r, const std::string & reason_r ) override
122 {
123 if ( not _oldRec || notStarted() ) return;
125 }
126
127 private:
128 // _isOptional also indicates the delayed start
129 bool notStarted() const
130 { return _isOptional; }
131
133 {
134 if ( _isOptional ) {
135 // we know _oldRec is valid...
136 _oldRec->start( _startFile, std::move(_startLocalfile) );
137 _isOptional = false;
138 }
139 }
140
141 private:
147 };
148
150 {
151 ProgressData( CURL *curl, time_t timeout = 0, zypp::Url url = zypp::Url(),
154
155 void updateStats( curl_off_t dltotal = 0.0, curl_off_t dlnow = 0.0 );
156
157 int reportProgress() const;
158
160 { return _curl; }
161
162 bool timeoutReached() const
163 { return _timeoutReached; }
164
165 bool fileSizeExceeded() const
166 { return _fileSizeExceeded; }
167
170
173
174 private:
177 time_t _timeout;
182
183 time_t _timeStart = 0;
184 time_t _timeLast = 0;
185 time_t _timeRcv = 0;
186 time_t _timeNow = 0;
187
188 curl_off_t _dnlTotal = 0.0;
189 curl_off_t _dnlLast = 0.0;
190 curl_off_t _dnlNow = 0.0;
191
192 int _dnlPercent= 0;
193
194 double _drateTotal= 0.0;
195 double _drateLast = 0.0;
196 };
197
198
199
201 : _curl( curl )
202 , _url(std::move( url ))
203 , _timeout( timeout )
204 , _timeoutReached( false )
205 , _fileSizeExceeded ( false )
206 , _expectedFileSize( expectedFileSize_r )
207 , report( _report )
208 {}
209
210 void ProgressData::updateStats( curl_off_t dltotal, curl_off_t dlnow )
211 {
212 time_t now = _timeNow = time(0);
213
214 // If called without args (0.0), recompute based on the last values seen
215 if ( dltotal && dltotal != _dnlTotal )
217
218 if ( dlnow && dlnow != _dnlNow )
219 {
220 _timeRcv = now;
221 _dnlNow = dlnow;
222 }
223
224 // init or reset if time jumps back
225 if ( !_timeStart || _timeStart > now )
226 _timeStart = _timeLast = _timeRcv = now;
227
228 // timeout condition
229 if ( _timeout )
230 _timeoutReached = ( (now - _timeRcv) > _timeout );
231
232 // check if the downloaded data is already bigger than what we expected
234
235 // percentage:
236 if ( _dnlTotal )
237 _dnlPercent = int( _dnlNow * 100 / _dnlTotal );
238
239 // download rates:
240 _drateTotal = double(_dnlNow) / std::max( int(now - _timeStart), 1 );
241
242 if ( _timeLast < now )
243 {
244 _drateLast = double(_dnlNow - _dnlLast) / int(now - _timeLast);
245 // start new period
246 _timeLast = now;
248 }
249 else if ( _timeStart == _timeLast )
251 }
252
254 {
255 if ( _fileSizeExceeded )
256 return 1;
257 if ( _timeoutReached )
258 return 1; // no-data timeout
259 if ( report && !(*report)->progress( _dnlPercent, _url, _drateTotal, _drateLast ) )
260 return 1; // user requested abort
261 return 0;
262 }
263
264 const char * anonymousIdHeader()
265 {
266 // we need to add the release and identifier to the
267 // agent string.
268 // The target could be not initialized, and then this information
269 // is guessed.
270 // bsc#1212187: HTTP/2 RFC 9113 forbids fields ending with a space
271 static const std::string _value( str::trim( str::form(
272 "X-ZYpp-AnonymousId: %s",
273 Target::anonymousUniqueId( Pathname()/*guess root*/ ).c_str()
274 )));
275 return _value.c_str();
276 }
277
279 {
280 // we need to add the release and identifier to the
281 // agent string.
282 // The target could be not initialized, and then this information
283 // is guessed.
284 // bsc#1212187: HTTP/2 RFC 9113 forbids fields ending with a space
285 static const std::string _value( str::trim( str::form(
286 "X-ZYpp-DistributionFlavor: %s",
287 Target::distributionFlavor( Pathname()/*guess root*/ ).c_str()
288 )));
289 return _value.c_str();
290 }
291
292 const char * agentString()
293 {
294 // we need to add the release and identifier to the
295 // agent string.
296 // The target could be not initialized, and then this information
297 // is guessed.
298 // bsc#1212187: HTTP/2 RFC 9113 forbids fields ending with a space
299 static const std::string _value( str::trim( str::form(
300 "ZYpp " LIBZYPP_VERSION_STRING " (curl %s) %s"
302 , Target::targetDistribution( Pathname()/*guess root*/ ).c_str()
303 )));
304 return _value.c_str();
305 }
306
311 {
312 public:
314 const std::string & err_r,
315 const std::string & msg_r )
316 : media::MediaCurlException( url_r, err_r, msg_r )
317 {}
318 //~MediaCurlExceptionMayRetryInternaly() noexcept {}
319 };
320
321}
322
323
324using namespace internal;
325using namespace zypp::base;
326
327namespace zypp {
328
329 namespace media {
330
331Pathname MediaCurl::_cookieFile = "/var/lib/YaST2/cookies";
332
333// we use this define to unbloat code as this C setting option
334// and catching exception is done frequently.
336#define SET_OPTION(opt,val) do { \
337 ret = curl_easy_setopt ( _curl, opt, val ); \
338 if ( ret != 0) { \
339 ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); \
340 } \
341 } while ( false )
342
343#define SET_OPTION_OFFT(opt,val) SET_OPTION(opt,(curl_off_t)val)
344#define SET_OPTION_LONG(opt,val) SET_OPTION(opt,(long)val)
345#define SET_OPTION_VOID(opt,val) SET_OPTION(opt,(void*)val)
346
350 "/", // urlpath at attachpoint
351 true ), // does_download
352 _curl( NULL ),
353 _customHeaders(0L)
354{
355 _curlError[0] = '\0';
356
357 MIL << "MediaCurl::MediaCurl(" << url_r << ", " << attach_point_hint_r << ")" << endl;
358
360
361 if( !attachPoint().empty())
362 {
364 Pathname apath(attachPoint() + "XXXXXX");
365 char *atemp = ::strdup( apath.asString().c_str());
366 char *atest = NULL;
367 if( !ainfo.isDir() || !ainfo.userMayRWX() ||
368 atemp == NULL || (atest=::mkdtemp(atemp)) == NULL)
369 {
370 WAR << "attach point " << ainfo.path()
371 << " is not useable for " << url_r.getScheme() << endl;
372 setAttachPoint("", true);
373 }
374 else if( atest != NULL)
375 ::rmdir(atest);
376
377 if( atemp != NULL)
378 ::free(atemp);
379 }
380}
381
383{
385}
386
391
392void MediaCurl::setCurlError(const char* error)
393{
394 // FIXME(dmllr): Use strlcpy if available for better performance
395 strncpy(_curlError, error, sizeof(_curlError)-1);
396 _curlError[sizeof(_curlError)-1] = '\0';
397}
398
400
401void MediaCurl::checkProtocol(const Url &url) const
402{
405 // curl_info does not need any free (is static)
406 if (curl_info->protocols)
407 {
408 const char * const *proto = nullptr;
409 std::string scheme( url.getScheme());
410 bool found = false;
411 for(proto=curl_info->protocols; !found && *proto; ++proto)
412 {
413 if( scheme == std::string((const char *)*proto))
414 found = true;
415 }
416 if( !found)
417 {
418 std::string msg("Unsupported protocol '");
419 msg += scheme;
420 msg += "'";
422 }
423 }
424}
425
427{
429
433 if ( ret != 0 ) {
434 ZYPP_THROW(MediaCurlSetOptException(_url, "Error setting error buffer"));
435 }
436
439
440 // create non persistant settings
441 // so that we don't add headers twice
443
444 // add custom headers for download.opensuse.org (bsc#955801)
445 if ( _url.getHost() == "download.opensuse.org" )
446 {
447 vol_settings.addHeader(anonymousIdHeader());
449 }
450 vol_settings.addHeader("Pragma:");
451
453
454 // fill some settings from url query parameters
455 try
456 {
458 }
459 catch ( const MediaException &e )
460 {
463 }
464 // if the proxy was not set (or explicitly unset) by url, then look...
465 if ( _settings.proxy().empty() )
466 {
467 // ...at the system proxy settings
469 }
470
473 {
476 }
477
482 // If a transfer timeout is set, also set CURLOPT_TIMEOUT to an upper limit
483 // just in case curl does not trigger its progress callback frequently
484 // enough.
485 if ( _settings.timeout() )
486 {
488 }
489
490 // follow any Location: header that the server sends as part of
491 // an HTTP header (#113275)
493 // 3 redirects seem to be too few in some cases (bnc #465532)
495
496 if ( _url.getScheme() == "https" )
497 {
500 }
501
504 {
506 }
507
509 {
511 }
512 if( ! _settings.clientKeyPath().empty() )
513 {
515 }
516
517#ifdef CURLSSLOPT_ALLOW_BEAST
518 // see bnc#779177
520 if ( ret != 0 ) {
523 }
524#endif
527 // bnc#903405 - POODLE: libzypp should only talk TLS
529 }
530
532
533 /* Fixes bsc#1174011 "auth=basic ignored in some cases"
534 * We should proactively add the password to the request if basic auth is configured
535 * and a password is available in the credentials but not in the URL.
536 *
537 * We will be a bit paranoid here and require that the URL has a user embedded, otherwise we go the default route
538 * and ask the server first about the auth method
539 */
540 if ( _settings.authType() == "basic"
541 && _settings.username().size()
542 && !_settings.password().size() ) {
543
545 const auto cred = cm.getCred( _url );
546 if ( cred && cred->valid() ) {
547 if ( !_settings.username().size() )
548 _settings.setUsername(cred->username());
549 _settings.setPassword(cred->password());
550 }
551 }
552
553 /*---------------------------------------------------------------*
554 CURLOPT_USERPWD: [user name]:[password]
555
556 Url::username/password -> CURLOPT_USERPWD
557 If not provided, anonymous FTP identification
558 *---------------------------------------------------------------*/
559
560 if ( _settings.userPassword().size() )
561 {
563 std::string use_auth = _settings.authType();
564 if (use_auth.empty())
565 use_auth = "digest,basic"; // our default
567 if( auth != CURLAUTH_NONE)
568 {
569 DBG << "Enabling HTTP authentication methods: " << use_auth
570 << " (CURLOPT_HTTPAUTH=" << auth << ")" << std::endl;
572 }
573 }
574
575 if ( _settings.proxyEnabled() && ! _settings.proxy().empty() )
576 {
577 DBG << "Proxy: '" << _settings.proxy() << "'" << endl;
580 /*---------------------------------------------------------------*
581 * CURLOPT_PROXYUSERPWD: [user name]:[password]
582 *
583 * Url::option(proxyuser and proxypassword) -> CURLOPT_PROXYUSERPWD
584 * If not provided, $HOME/.curlrc is evaluated
585 *---------------------------------------------------------------*/
586
587 std::string proxyuserpwd = _settings.proxyUserPassword();
588
589 if ( proxyuserpwd.empty() )
590 {
592 CurlConfig::parseConfig(curlconf); // parse ~/.curlrc
593 if ( curlconf.proxyuserpwd.empty() )
594 DBG << "Proxy: ~/.curlrc does not contain the proxy-user option" << endl;
595 else
596 {
597 proxyuserpwd = curlconf.proxyuserpwd;
598 DBG << "Proxy: using proxy-user from ~/.curlrc" << endl;
599 }
600 }
601 else
602 {
603 DBG << "Proxy: using provided proxy-user '" << _settings.proxyUsername() << "'" << endl;
604 }
605
606 if ( ! proxyuserpwd.empty() )
607 {
608 SET_OPTION(CURLOPT_PROXYUSERPWD, curlUnEscape( proxyuserpwd ).c_str());
609 }
610 }
611#if CURLVERSION_AT_LEAST(7,19,4)
612 else if ( _settings.proxy() == EXPLICITLY_NO_PROXY )
613 {
614 // Explicitly disabled in URL (see fillSettingsFromUrl()).
615 // This should also prevent libcurl from looking into the environment.
616 DBG << "Proxy: explicitly NOPROXY" << endl;
618 }
619#endif
620 else
621 {
622 DBG << "Proxy: not explicitly set" << endl;
623 DBG << "Proxy: libcurl may look into the environment" << endl;
624 }
625
627 if ( _settings.minDownloadSpeed() != 0 )
628 {
630 // default to 10 seconds at low speed
632 }
633
634#if CURLVERSION_AT_LEAST(7,15,5)
635 if ( _settings.maxDownloadSpeed() != 0 )
637#endif
638
639 /*---------------------------------------------------------------*
640 *---------------------------------------------------------------*/
641
642 _currentCookieFile = _cookieFile.asString();
643 if ( ::geteuid() == 0 || PathInfo(_currentCookieFile).owner() == ::geteuid() )
645
646 const auto &cookieFileParam = _url.getQueryParam( "cookies" );
647 if ( !cookieFileParam.empty() && str::strToBool( cookieFileParam, true ) )
649 else
650 MIL << "No cookies requested" << endl;
654
655#if CURLVERSION_AT_LEAST(7,18,0)
656 // bnc #306272
658#endif
659 // Append settings custom headers to curl.
660 // TransferSettings assert strings are trimmed (HTTP/2 RFC 9113)
661 for ( const auto &header : vol_settings.headers() ) {
663 if ( !_customHeaders )
665 }
667}
668
670
671
672void MediaCurl::attachTo (bool next)
673{
674 if ( next )
676
677 if ( !_url.isValid() )
679
682 {
684 }
685
686 disconnectFrom(); // clean _curl if needed
688 if ( !_curl ) {
690 }
691 try
692 {
693 setupEasy();
694 }
695 catch (Exception & ex)
696 {
699 }
700
701 // FIXME: need a derived class to propelly compare url's
703 setMediaSource(media);
704}
705
706bool
708{
709 return MediaHandler::checkAttachPoint( apoint, true, true);
710}
711
713
715{
716 if ( _customHeaders )
717 {
719 _customHeaders = 0L;
720 }
721
722 if ( _curl )
723 {
724 // bsc#1201092: Strange but within global_dtors we may exceptions here.
725 try { curl_easy_cleanup( _curl ); }
726 catch (...) { ; }
727 _curl = NULL;
728 }
729}
730
732
733void MediaCurl::releaseFrom( const std::string & ejectDev )
734{
735 disconnect();
736}
737
739
740void MediaCurl::getFile( const OnMediaLocation &file ) const
741{
742 // Use absolute file name to prevent access of files outside of the
743 // hierarchy below the attach point.
744 getFileCopy( file, localPath(file.filename()).absolutename() );
745}
746
748
749void MediaCurl::getFileCopy( const OnMediaLocation & srcFile , const Pathname & target ) const
750{
751
752 const auto &filename = srcFile.filename();
753
754 // Optional files will send no report until data are actually received (we know it exists).
757
758 Url fileurl(getFileUrl(filename));
759
760 bool firstAuth = true; // bsc#1210870: authenticate must not return stored credentials more than once.
761 unsigned internalTry = 0;
762 static constexpr unsigned maxInternalTry = 3;
763
764 do
765 {
766 try
767 {
768 doGetFileCopy( srcFile, target, report );
769 break; // success!
770 }
771 // retry with proper authentication data
773 {
774 if ( authenticate(ex_r.hint(), firstAuth) ) {
775 firstAuth = false; // must not return stored credentials again
776 continue; // retry
777 }
778
779 report->finish(fileurl, zypp::media::DownloadProgressReport::ACCESS_DENIED, ex_r.asUserHistory());
781 }
782 // unexpected exception
783 catch (MediaException & excpt_r)
784 {
785 if ( typeid(excpt_r) == typeid( MediaCurlExceptionMayRetryInternaly ) ) {
786 ++internalTry;
787 if ( internalTry < maxInternalTry ) {
788 // just report (NO_ERROR); no interactive request to the user
789 report->problem(fileurl, media::DownloadProgressReport::NO_ERROR, excpt_r.asUserHistory()+_("Will try again..."));
790 continue; // retry
791 }
792 excpt_r.addHistory( str::Format(_("Giving up after %1% attempts.")) % maxInternalTry );
793 }
794
796 if( typeid(excpt_r) == typeid( media::MediaFileNotFoundException ) ||
797 typeid(excpt_r) == typeid( media::MediaNotAFileException ) )
798 {
800 }
801 report->finish(fileurl, reason, excpt_r.asUserHistory());
803 }
804 }
805 while ( true );
807}
808
810
811bool MediaCurl::getDoesFileExist( const Pathname & filename ) const
812{
813 bool retry = false;
814
815 do
816 {
817 try
818 {
819 return doGetDoesFileExist( filename );
820 }
821 // authentication problem, retry with proper authentication data
823 {
824 if(authenticate(ex_r.hint(), !retry))
825 retry = true;
826 else
828 }
829 // unexpected exception
830 catch (MediaException & excpt_r)
831 {
833 }
834 }
835 while (retry);
836
837 return false;
838}
839
841
843 CURLcode code,
844 bool timeout_reached) const
845{
846 if ( code != 0 )
847 {
848 Url url;
849 if (filename.empty())
850 url = _url;
851 else
852 url = getFileUrl(filename);
853
854 std::string err;
855 {
856 switch ( code )
857 {
859 err = " Unsupported protocol";
860 if ( !_lastRedirect.empty() )
861 {
862 err += " or redirect (";
863 err += _lastRedirect;
864 err += ")";
865 }
866 break;
869 err = " Bad URL";
870 break;
873 MediaUnauthorizedException(url, "Login failed.", _curlError, ""));
874 break;
876 {
877 long httpReturnCode = 0;
881 if ( infoRet == CURLE_OK )
882 {
883 std::string msg = "HTTP response: " + str::numstring( httpReturnCode );
884 switch ( httpReturnCode )
885 {
886 case 401:
887 {
888 std::string auth_hint = getAuthHint();
889
890 DBG << msg << " Login failed (URL: " << url.asString() << ")" << std::endl;
891 DBG << "MediaUnauthorizedException auth hint: '" << auth_hint << "'" << std::endl;
892
894 url, "Login failed.", _curlError, auth_hint
895 ));
896 }
897
898 case 502: // bad gateway (bnc #1070851)
899 case 503: // service temporarily unavailable (bnc #462545)
901 case 504: // gateway timeout
903 case 403:
904 {
905 std::string msg403;
906 if ( url.getHost().find(".suse.com") != std::string::npos )
907 msg403 = _("Visit the SUSE Customer Center to check whether your registration is valid and has not expired.");
908 else if (url.asString().find("novell.com") != std::string::npos)
909 msg403 = _("Visit the Novell Customer Center to check whether your registration is valid and has not expired.");
911 }
912 case 404:
913 case 410:
915 }
916
917 DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
919 }
920 else
921 {
922 std::string msg = "Unable to retrieve HTTP response:";
923 DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
925 }
926 }
927 break;
929#if CURLVERSION_AT_LEAST(7,16,0)
931#endif
934 err = "File not found";
936 break;
939 err = "Login failed";
940 break;
945 err = "Connection failed";
946 break;
948 err = "Write error";
949 break;
952 timeout_reached = true; // fall though to TimeoutException
953 // fall though...
955 if( timeout_reached )
956 {
957 err = "Timeout reached";
959 }
960 else
961 {
962 err = "User abort";
963 }
964 break;
965
966 default:
967 err = "Curl error " + str::numstring( code );
968 break;
969 }
970
971 // uhm, no 0 code but unknown curl exception
973 }
974 }
975 else
976 {
977 // actually the code is 0, nothing happened
978 }
979}
980
982
983bool MediaCurl::doGetDoesFileExist( const Pathname & filename ) const
984{
985 DBG << filename.asString() << endl;
986
987 if(!_url.isValid())
989
990 if(_url.getHost().empty())
992
993 Url url(getFileUrl(filename));
994
995 DBG << "URL: " << url.asString() << endl;
996 // Use URL without options and without username and passwd
997 // (some proxies dislike them in the URL).
998 // Curl seems to need the just scheme, hostname and a path;
999 // the rest was already passed as curl options (in attachTo).
1001
1002 //
1003 // See also Bug #154197 and ftp url definition in RFC 1738:
1004 // The url "ftp://user@host/foo/bar/file" contains a path,
1005 // that is relative to the user's home.
1006 // The url "ftp://user@host//foo/bar/file" (or also with
1007 // encoded slash as %2f) "ftp://user@host/%2ffoo/bar/file"
1008 // contains an absolute path.
1009 //
1010 _lastRedirect.clear();
1011 std::string urlBuffer( curlUrl.asString());
1013 urlBuffer.c_str() );
1014 if ( ret != 0 ) {
1016 }
1017
1018 // If no head requests allowed (?head_requests=no):
1019 // Instead of returning no data with NOBODY, we return
1020 // little data, that works with broken servers, and
1021 // works for ftp as well, because retrieving only headers
1022 // ftp will return always OK code ?
1023 // See http://curl.haxx.se/docs/knownbugs.html #58
1025 struct TempSetHeadRequest
1026 {
1029 if ( _doHttpHeadRequest ) {
1030 curl_easy_setopt( _curl, CURLOPT_NOBODY, 1L );
1031 } else {
1032 curl_easy_setopt( _curl, CURLOPT_RANGE, "0-1" );
1033 }
1034 }
1035 TempSetHeadRequest(const TempSetHeadRequest &) = delete;
1037 TempSetHeadRequest &operator=(const TempSetHeadRequest &) = delete;
1038 TempSetHeadRequest &operator=(TempSetHeadRequest &&) = delete;
1040 if ( _doHttpHeadRequest ) {
1042 /* yes, this is why we never got to get NOBODY working before,
1043 because setting it changes this option too, and we also*
1044 need to reset it
1045 See: http://curl.haxx.se/mail/archive-2005-07/0073.html
1046 */
1047 curl_easy_setopt( _curl, CURLOPT_HTTPGET, 1L );
1048 } else {
1050 }
1051 }
1052 private:
1053 CURL * _curl;
1054 bool _doHttpHeadRequest;
1055 } _guard( _curl, (_url.getScheme() == "http" || _url.getScheme() == "https") && _settings.headRequestsAllowed() );
1056
1057
1058 AutoFILE file { ::fopen( "/dev/null", "w" ) };
1059 if ( !file ) {
1060 ERR << "fopen failed for /dev/null" << endl;
1061 ZYPP_THROW(MediaWriteException("/dev/null"));
1062 }
1063
1065 if ( ret != 0 ) {
1067 }
1068
1070 MIL << "perform code: " << ok << " [ " << curl_easy_strerror(ok) << " ]" << endl;
1071
1072 // as we are not having user interaction, the user can't cancel
1073 // the file existence checking, a callback or timeout return code
1074 // will be always a timeout.
1075 try {
1076 evaluateCurlCode( filename, ok, true /* timeout */);
1077 }
1078 catch ( const MediaFileNotFoundException &e ) {
1079 // if the file did not exist then we can return false
1080 return false;
1081 }
1082 catch ( const MediaException &e ) {
1083 // some error, we are not sure about file existence, rethrw
1084 ZYPP_RETHROW(e);
1085 }
1086 // exists
1087 return ( ok == CURLE_OK );
1088}
1089
1091
1093{
1094 Pathname dest = target.absolutename();
1095 if( assert_dir( dest.dirname() ) )
1096 {
1097 DBG << "assert_dir " << dest.dirname() << " failed" << endl;
1098 ZYPP_THROW( MediaSystemException(getFileUrl(srcFile.filename()), "System error on " + dest.dirname().asString()) );
1099 }
1100
1101 ManagedFile destNew { target.extend( ".new.zypp.XXXXXX" ) };
1102 AutoFILE file;
1103 {
1104 AutoFREE<char> buf { ::strdup( (*destNew).c_str() ) };
1105 if( ! buf )
1106 {
1107 ERR << "out of memory for temp file name" << endl;
1108 ZYPP_THROW(MediaSystemException(getFileUrl(srcFile.filename()), "out of memory for temp file name"));
1109 }
1110
1112 if( tmp_fd == -1 )
1113 {
1114 ERR << "mkstemp failed for file '" << destNew << "'" << endl;
1116 }
1118
1119 file = ::fdopen( tmp_fd, "we" );
1120 if ( ! file )
1121 {
1122 ERR << "fopen failed for file '" << destNew << "'" << endl;
1124 }
1125 tmp_fd.resetDispose(); // don't close it here! ::fdopen moved ownership to file
1126 }
1127
1128 DBG << "dest: " << dest << endl;
1129 DBG << "temp: " << destNew << endl;
1130
1131 // set IFMODSINCE time condition (no download if not modified)
1132 if( PathInfo(target).isExist() && !(options & OPTION_NO_IFMODSINCE) )
1133 {
1135 curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, (long)PathInfo(target).mtime());
1136 }
1137 else
1138 {
1141 }
1142 try
1143 {
1144 doGetFileCopyFile( srcFile, dest, file, report, options);
1145 }
1146 catch (Exception &e)
1147 {
1150 ZYPP_RETHROW(e);
1151 }
1152
1153 long httpReturnCode = 0;
1157 bool modified = true;
1158 if (infoRet == CURLE_OK)
1159 {
1160 DBG << "HTTP response: " + str::numstring(httpReturnCode);
1161 if ( httpReturnCode == 304
1162 || ( httpReturnCode == 213 && (_url.getScheme() == "ftp" || _url.getScheme() == "tftp") ) ) // not modified
1163 {
1164 DBG << " Not modified.";
1165 modified = false;
1166 }
1167 DBG << endl;
1168 }
1169 else
1170 {
1171 WAR << "Could not get the response code." << endl;
1172 }
1173
1174 if (modified || infoRet != CURLE_OK)
1175 {
1176 // apply umask
1177 if ( ::fchmod( ::fileno(file), filesystem::applyUmaskTo( 0644 ) ) )
1178 {
1179 ERR << "Failed to chmod file " << destNew << endl;
1180 }
1181
1182 file.resetDispose(); // we're going to close it manually here
1183 if ( ::fclose( file ) )
1184 {
1185 ERR << "Fclose failed for file '" << destNew << "'" << endl;
1187 }
1188
1189 // move the temp file into dest
1190 if ( rename( destNew, dest ) != 0 ) {
1191 ERR << "Rename failed" << endl;
1193 }
1194 destNew.resetDispose(); // no more need to unlink it
1195 }
1196
1197 DBG << "done: " << PathInfo(dest) << endl;
1198}
1199
1201
1203{
1204 DBG << srcFile.filename().asString() << endl;
1205
1206 if(!_url.isValid())
1208
1209 if(_url.getHost().empty())
1211
1212 Url url(getFileUrl(srcFile.filename()));
1213
1214 DBG << "URL: " << url.asString() << endl;
1215 // Use URL without options and without username and passwd
1216 // (some proxies dislike them in the URL).
1217 // Curl seems to need the just scheme, hostname and a path;
1218 // the rest was already passed as curl options (in attachTo).
1220
1221 //
1222 // See also Bug #154197 and ftp url definition in RFC 1738:
1223 // The url "ftp://user@host/foo/bar/file" contains a path,
1224 // that is relative to the user's home.
1225 // The url "ftp://user@host//foo/bar/file" (or also with
1226 // encoded slash as %2f) "ftp://user@host/%2ffoo/bar/file"
1227 // contains an absolute path.
1228 //
1229 _lastRedirect.clear();
1230 std::string urlBuffer( curlUrl.asString());
1232 urlBuffer.c_str() );
1233 if ( ret != 0 ) {
1235 }
1236
1238 if ( ret != 0 ) {
1240 }
1241
1242 // Set callback and perform.
1244 if (!(options & OPTION_NO_REPORT_START))
1245 report->start(url, dest);
1247 WAR << "Can't set CURLOPT_PROGRESSDATA: " << _curlError << endl;;
1248 }
1249
1250 ret = executeCurl();
1251#if CURLVERSION_AT_LEAST(7,19,4)
1252 // bnc#692260: If the client sends a request with an If-Modified-Since header
1253 // with a future date for the server, the server may respond 200 sending a
1254 // zero size file.
1255 // curl-7.19.4 introduces CURLINFO_CONDITION_UNMET to check this condition.
1256 if ( ftell(file) == 0 && ret == 0 )
1257 {
1258 long httpReturnCode = 33;
1260 {
1261 long conditionUnmet = 33;
1263 {
1264 WAR << "TIMECONDITION unmet - retry without." << endl;
1267 ret = executeCurl();
1268 }
1269 }
1270 }
1271#endif
1272
1274 WAR << "Can't unset CURLOPT_PROGRESSDATA: " << _curlError << endl;;
1275 }
1276
1277 if ( ret != 0 )
1278 {
1279 ERR << "curl error: " << ret << ": " << _curlError
1280 << ", temp file size " << ftell(file)
1281 << " bytes." << endl;
1282
1283 // the timeout is determined by the progress data object
1284 // which holds whether the timeout was reached or not,
1285 // otherwise it would be a user cancel
1286 try {
1287
1288 if ( progressData.fileSizeExceeded() )
1290
1291 evaluateCurlCode( srcFile.filename(), ret, progressData.timeoutReached() );
1292 }
1293 catch ( const MediaException &e ) {
1294 // some error, we are not sure about file existence, rethrw
1295 ZYPP_RETHROW(e);
1296 }
1297 }
1298}
1299
1301
1302void MediaCurl::getDir( const Pathname & dirname, bool recurse_r ) const
1303{
1304 filesystem::DirContent content;
1305 getDirInfo( content, dirname, /*dots*/false );
1306
1307 for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
1308 Pathname filename = dirname + it->name;
1309 int res = 0;
1310
1311 switch ( it->type ) {
1312 case filesystem::FT_NOT_AVAIL: // old directory.yast contains no typeinfo at all
1314 getFile( OnMediaLocation( filename ) );
1315 break;
1316 case filesystem::FT_DIR: // newer directory.yast contain at least directory info
1317 if ( recurse_r ) {
1318 getDir( filename, recurse_r );
1319 } else {
1320 res = assert_dir( localPath( filename ) );
1321 if ( res ) {
1322 WAR << "Ignore error (" << res << ") on creating local directory '" << localPath( filename ) << "'" << endl;
1323 }
1324 }
1325 break;
1326 default:
1327 // don't provide devices, sockets, etc.
1328 break;
1329 }
1330 }
1331}
1332
1334
1335void MediaCurl::getDirInfo( std::list<std::string> & retlist,
1336 const Pathname & dirname, bool dots ) const
1337{
1338 getDirectoryYast( retlist, dirname, dots );
1339}
1340
1342
1344 const Pathname & dirname, bool dots ) const
1345{
1346 getDirectoryYast( retlist, dirname, dots );
1347}
1348
1350//
1351int MediaCurl::aliveCallback( void *clientp, curl_off_t /*dltotal*/, curl_off_t dlnow, curl_off_t /*ultotal*/, curl_off_t /*ulnow*/ )
1352{
1354 if( pdata )
1355 {
1356 // Do not propagate dltotal in alive callbacks. MultiCurl uses this to
1357 // prevent a percentage raise while downloading a metalink file. Download
1358 // activity however is indicated by propagating the download rate (via dlnow).
1359 pdata->updateStats( 0.0, dlnow );
1360 return pdata->reportProgress();
1361 }
1362 return 0;
1363}
1364
1365int MediaCurl::progressCallback( void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow )
1366{
1368 if( pdata )
1369 {
1370 // work around curl bug that gives us old data
1371 long httpReturnCode = 0;
1374
1375 pdata->updateStats( dltotal, dlnow );
1376 return pdata->reportProgress();
1377 }
1378 return 0;
1379}
1380
1382{
1384 return pdata ? pdata->curl() : 0;
1385}
1386
1388
1389std::string MediaCurl::getAuthHint() const
1390{
1391 long auth_info = CURLAUTH_NONE;
1392
1395
1396 if(infoRet == CURLE_OK)
1397 {
1399 }
1400
1401 return "";
1402}
1403
1408void MediaCurl::resetExpectedFileSize(void *clientp, const ByteCount &expectedFileSize)
1409{
1410 internal::ProgressData *data = reinterpret_cast<internal::ProgressData *>(clientp);
1411 if ( data ) {
1412 data->expectedFileSize( expectedFileSize );
1413 }
1414}
1415
1422{
1423 // initialize our helpers
1426 ,[](auto &releaseMe ){ if (releaseMe._multi) curl_multi_cleanup(releaseMe._multi); }
1427 );
1428
1429 if (!cMulti->_multi)
1431
1432 // we could derive from that, but currently that does not make a lot of sense
1434
1435 // add the easy handle to the multi instance
1436 if ( curl_multi_add_handle( cMulti->_multi, _curl ) != CURLM_OK )
1437 ZYPP_THROW(MediaCurlException( _url, "curl_multi_add_handle", "unknown error"));
1438
1439 // make sure the handle is cleanly removed from the multi handle
1441
1442 // kickstart curl, this will cause libcurl to go over the added handles and register sockets and timeouts
1443 CURLMcode mcode = _curlHelper.handleTimout();
1444 if (mcode != CURLM_OK)
1445 ZYPP_THROW(MediaCurlException( _url, "curl_multi_socket_action", "unknown error"));
1446
1447 bool canContinue = true;
1448 while ( canContinue ) {
1449
1450 // copy watched sockets in case curl changes the vector as we go over the events later
1451 std::vector<GPollFD> requestedFds = _curlHelper.socks;
1452
1453 int r = zypp_detail::zypp_poll( requestedFds, _curlHelper.timeout_ms.value_or( -1 ) );
1454 if ( r == -1 )
1455 ZYPP_THROW( MediaCurlException(_url, "zypp_poll() failed", "unknown error") );
1456
1457 // run curl
1458 if ( r == 0 ) {
1459 CURLMcode mcode = _curlHelper.handleTimout();
1460 if (mcode != CURLM_OK)
1461 ZYPP_THROW(MediaCurlException(_url, "curl_multi_socket_action", "unknown error"));
1462 } else {
1463 CURLMcode mcode = _curlHelper.handleSocketActions( requestedFds );
1464 if (mcode != CURLM_OK)
1465 ZYPP_THROW(MediaCurlException(_url, "curl_multi_socket_action", "unknown error"));
1466 }
1467
1468 CURLMsg *msg = nullptr;
1469 int nqueue = 0;
1470 while ((msg = curl_multi_info_read( cMulti->_multi, &nqueue)) != 0) {
1471 if ( msg->msg != CURLMSG_DONE ) continue;
1472 if ( msg->easy_handle != _curl ) continue;
1473
1474 return msg->data.result;
1475 }
1476 }
1477 return CURLE_OK;
1478}
1479
1481
1482bool MediaCurl::authenticate(const std::string & availAuthTypes, bool firstTry) const
1483{
1487
1488 // get stored credentials
1489 AuthData_Ptr cmcred = cm.getCred(_url);
1490
1491 if (cmcred && firstTry)
1492 {
1494 DBG << "got stored credentials:" << endl << *credentials << endl;
1495 }
1496 // if not found, ask user
1497 else
1498 {
1499
1503
1504 // preset the username if present in current url
1505 if (!_url.getUsername().empty() && firstTry)
1506 curlcred->setUsername(_url.getUsername());
1507 // if CM has found some credentials, preset the username from there
1508 else if (cmcred)
1509 curlcred->setUsername(cmcred->username());
1510
1511 // indicate we have no good credentials from CM
1512 cmcred.reset();
1513
1514 std::string prompt_msg = str::Format(_("Authentication required for '%s'")) % _url.asString();
1515
1516 // set available authentication types from the exception
1517 // might be needed in prompt
1518 curlcred->setAuthType(availAuthTypes);
1519
1520 // ask user
1521 if (auth_report->prompt(_url, prompt_msg, *curlcred))
1522 {
1523 DBG << "callback answer: retry" << endl
1524 << "CurlAuthData: " << *curlcred << endl;
1525
1526 if (curlcred->valid())
1527 {
1529 // if (credentials->username() != _url.getUsername())
1530 // _url.setUsername(credentials->username());
1538 }
1539 }
1540 else
1541 {
1542 DBG << "callback answer: cancel" << endl;
1543 }
1544 }
1545
1546 // set username and password
1547 if (credentials)
1548 {
1549 // HACK, why is this const?
1550 const_cast<MediaCurl*>(this)->_settings.setUsername(credentials->username());
1551 const_cast<MediaCurl*>(this)->_settings.setPassword(credentials->password());
1552
1553 // set username and password
1556
1557 // set available authentication types from the exception
1558 if (credentials->authType() == CURLAUTH_NONE)
1559 credentials->setAuthType(availAuthTypes);
1560
1561 // set auth type (seems this must be set _after_ setting the userpwd)
1562 if (credentials->authType() != CURLAUTH_NONE)
1563 {
1564 // FIXME: only overwrite if not empty?
1565 const_cast<MediaCurl*>(this)->_settings.setAuthType(credentials->authTypeAsString());
1568 }
1569
1570 if (!cmcred)
1571 {
1572 credentials->setUrl(_url);
1573 cm.addCred(*credentials);
1574 cm.save();
1575 }
1576
1577 return true;
1578 }
1579
1580 return false;
1581}
1582
1583//need a out of line definiton, otherwise vtable is emitted for every translation unit
1585
1586 } // namespace media
1587} // namespace zypp
1588//
#define SET_OPTION_OFFT(opt, val)
Definition MediaCurl.cc:343
#define SET_OPTION(opt, val)
Definition MediaCurl.cc:336
Edition * _value
TrueBool _guard
Attempt to work around certain issues by autoretry in MediaCurl::getFileCopy E.g.
Definition MediaCurl.cc:311
MediaCurlExceptionMayRetryInternaly(const Url &url_r, const std::string &err_r, const std::string &msg_r)
Definition MediaCurl.cc:313
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.
void reset()
Reset to default Ctor values.
Store and operate with byte count.
Definition ByteCount.h:32
Base class for Exception.
Definition Exception.h:147
const char * c_str() const
Describes a resource file located on a medium.
const Pathname & filename() const
The path to the resource on the medium.
ProgressData()
Ctor no range [0,0](0).
std::string distributionFlavor() const
This is flavor attribute of the installed base product but does not require the target to be loaded a...
Definition Target.cc:127
std::string anonymousUniqueId() const
anonymous unique id
Definition Target.cc:132
std::string targetDistribution() const
This is register.target attribute of the installed base product.
Definition Target.cc:102
Url manipulation class.
Definition Url.h:92
std::string getScheme() const
Returns the scheme name of the URL.
Definition Url.cc:537
std::string asString() const
Returns a default string representation of the Url object.
Definition Url.cc:501
std::string getUsername(EEncoding eflag=zypp::url::E_DECODED) const
Returns the username from the URL authority.
Definition Url.cc:576
std::string getQueryParam(const std::string &param, EEncoding eflag=zypp::url::E_DECODED) const
Return the value for the specified query parameter.
Definition Url.cc:664
std::string getHost(EEncoding eflag=zypp::url::E_DECODED) const
Returns the hostname or IP from the URL authority.
Definition Url.cc:592
bool isValid() const
Verifies the Url.
Definition Url.cc:493
static ZConfig & instance()
Singleton ctor.
Definition ZConfig.cc:925
Typesafe passing of user data via callbacks.
Definition UserData.h:40
Wrapper class for stat/lstat.
Definition PathInfo.h:222
Pathname extend(const std::string &r) const
Append string r to the last component of the path.
Definition Pathname.h:175
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
Pathname absolutename() const
Return this path, adding a leading '/' if relative.
Definition Pathname.h:141
Curl HTTP authentication data.
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)
Implementation class for FTP, HTTP and HTTPS MediaHandler.
Definition MediaCurl.h:32
virtual void setupEasy()
initializes the curl easy handle with the data from the url
Definition MediaCurl.cc:426
static void setCookieFile(const Pathname &)
Definition MediaCurl.cc:387
bool getDoesFileExist(const Pathname &filename) const override
Repeatedly calls doGetDoesFileExist() until it successfully returns, fails unexpectedly,...
Definition MediaCurl.cc:811
@ OPTION_NO_IFMODSINCE
to not add a IFMODSINCE header if target exists
Definition MediaCurl.h:43
@ OPTION_NO_REPORT_START
do not send a start ProgressReport
Definition MediaCurl.h:45
void getFile(const OnMediaLocation &file) const override
Call concrete handler to provide file below attach point.
Definition MediaCurl.cc:740
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:163
static Pathname _cookieFile
Definition MediaCurl.h:164
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.
void getFileCopy(const OnMediaLocation &srcFile, const Pathname &targetFilename) const override
Definition MediaCurl.cc:749
virtual void doGetFileCopy(const OnMediaLocation &srcFile, const Pathname &targetFilename, callback::SendReport< DownloadProgressReport > &_report, RequestOptions options=OPTION_NONE) const
std::string _lastRedirect
to log/report redirections
Definition MediaCurl.h:167
Url clearQueryString(const Url &url) const
Definition MediaCurl.cc:382
void attachTo(bool next=false) override
Call concrete handler to attach the media.
Definition MediaCurl.cc:672
void getDirInfo(std::list< std::string > &retlist, const Pathname &dirname, bool dots=true) const override
Call concrete handler to provide a content list of directory on media via retlist.
char _curlError[CURL_ERROR_SIZE]
Definition MediaCurl.h:165
void doGetFileCopyFile(const OnMediaLocation &srcFile, const Pathname &dest, FILE *file, callback::SendReport< DownloadProgressReport > &report, RequestOptions options=OPTION_NONE) const
void checkProtocol(const Url &url) const
check the url is supported by the curl library
Definition MediaCurl.cc:401
MediaCurl(const Url &url_r, const Pathname &attach_point_hint_r)
Definition MediaCurl.cc:347
CURLcode executeCurl() const
void evaluateCurlCode(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:842
bool checkAttachPoint(const Pathname &apoint) const override
Verify if the specified directory as attach point (root) as requires by the particular media handler ...
Definition MediaCurl.cc:707
void getDir(const Pathname &dirname, bool recurse_r) const override
Call concrete handler to provide directory content (not recursive!) below attach point.
void setCurlError(const char *error)
Definition MediaCurl.cc:392
bool authenticate(const std::string &availAuthTypes, bool firstTry) const
static CURL * progressCallback_getcurl(void *clientp)
void releaseFrom(const std::string &ejectDev) override
Call concrete handler to release the media.
Definition MediaCurl.cc:733
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:714
virtual bool doGetDoesFileExist(const Pathname &filename) const
Definition MediaCurl.cc:983
curl_slist * _customHeaders
Definition MediaCurl.h:171
std::string getAuthHint() const
Return a comma separated list of available authentication methods supported by server.
Just inherits Exception to separate media exceptions.
bool isUseableAttachPoint(const Pathname &path, bool mtab=true) const
Ask media manager, if the specified path is already used as attach point or if there are another atta...
Url url() const
Url used.
virtual bool checkAttachPoint(const Pathname &apoint) const
Verify if the specified directory as attach point (root) as requires by the particular media handler ...
void disconnect()
Use concrete handler to isconnect media.
Pathname createAttachPoint() const
Try to create a default / temporary attach point.
void setMediaSource(const MediaSourceRef &ref)
Set new media source reference.
Pathname localPath(const Pathname &pathname) const
Files provided will be available at 'localPath(filename)'.
const Url _url
Url to handle.
void getDirectoryYast(std::list< std::string > &retlist, const Pathname &dirname, bool dots=true) const
Retrieve and if available scan dirname/directory.yast.
void setAttachPoint(const Pathname &path, bool temp)
Set a new attach point.
Pathname attachPoint() const
Return the currently used attach point.
Common baseclass for MediaCurl and MediaNetwork.
Url getFileUrl(const Pathname &filename) const
concatenate the attach url and the filename to a complete download url
Media source internally used by MediaManager and MediaHandler.
Definition MediaSource.h:38
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 std::string & proxy() const
proxy host
const Pathname & clientKeyPath() const
SSL client key file.
void setUserAgentString(std::string &&val_r)
sets the user agent ie: "Mozilla v3" (trims)
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 headRequestsAllowed() const
whether HEAD requests are allowed
bool proxyEnabled() const
proxy is enabled
const std::string & username() const
auth username
const std::string & proxyUsername() const
proxy auth username
void setAuthType(const std::string &val_r)
set the allowed authentication types
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
void fillSettingsFromUrl(const Url &url, media::TransferSettings &s)
Fills the settings structure using options passed on the url for example ?timeout=x&proxy=foo.
size_t log_redirects_curl(char *ptr, size_t size, size_t nmemb, void *userdata)
const char * anonymousIdHeader()
Definition MediaCurl.cc:264
void globalInitCurlOnce()
Definition curlhelper.cc:64
const char * distributionFlavorHeader()
Definition MediaCurl.cc:278
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)
const char * agentString()
Definition MediaCurl.cc:292
void fillSettingsSystemProxy(const Url &url, media::TransferSettings &s)
Reads the system proxy configuration and fills the settings structure proxy information.
Url clearQueryString(const Url &url)
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:798
std::list< DirEntry > DirContent
Returned by readdir.
Definition PathInfo.h:519
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
shared_ptr< AuthData > AuthData_Ptr
Definition authdata.h:81
std::string numstring(char n, int w=0)
Definition String.h:289
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition String.cc:37
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
Definition String.h:429
std::string trim(const std::string &s, const Trim trim_r)
Definition String.cc:224
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
zypp::Url _url
Bottleneck filtering all DownloadProgressReport issued from Media[Muli]Curl.
Definition MediaCurl.cc:54
void report(const UserData &userData_r=UserData()) override
The most generic way of sending/receiving data.
Definition MediaCurl.cc:80
Action problem(const Url &file_r, Error error_r, const std::string &description_r) override
Definition MediaCurl.cc:115
OptionalDownloadProgressReport & operator=(const OptionalDownloadProgressReport &)=delete
OptionalDownloadProgressReport(bool isOptional=false)
Definition MediaCurl.cc:57
std::chrono::steady_clock::time_point TimePoint
Definition MediaCurl.cc:55
OptionalDownloadProgressReport(OptionalDownloadProgressReport &&)=delete
void finish(const Url &file_r, Error error_r, const std::string &reason_r) override
Definition MediaCurl.cc:121
bool progress(int value_r, const Url &file_r, double dbps_avg_r=-1, double dbps_current_r=-1) override
Download progress.
Definition MediaCurl.cc:96
OptionalDownloadProgressReport(const OptionalDownloadProgressReport &)=delete
void start(const Url &file_r, Pathname localfile_r) override
Definition MediaCurl.cc:84
ByteCount _expectedFileSize
Definition MediaCurl.cc:180
curl_off_t _dnlNow
Bytes downloaded now.
Definition MediaCurl.cc:190
int _dnlPercent
Percent completed or 0 if _dnlTotal is unknown.
Definition MediaCurl.cc:192
time_t _timeRcv
Start of no-data timeout.
Definition MediaCurl.cc:185
ByteCount expectedFileSize() const
Definition MediaCurl.cc:168
time_t _timeLast
Start last period(~1sec)
Definition MediaCurl.cc:184
int reportProgress() const
Definition MediaCurl.cc:253
double _drateLast
Download rate in last period.
Definition MediaCurl.cc:195
bool timeoutReached() const
Definition MediaCurl.cc:162
void expectedFileSize(ByteCount newval_r)
Definition MediaCurl.cc:171
curl_off_t _dnlLast
Bytes downloaded at period start.
Definition MediaCurl.cc:189
bool fileSizeExceeded() const
Definition MediaCurl.cc:165
void updateStats(curl_off_t dltotal=0.0, curl_off_t dlnow=0.0)
Definition MediaCurl.cc:210
double _drateTotal
Download rate so far.
Definition MediaCurl.cc:194
zypp::callback::SendReport< zypp::media::DownloadProgressReport > * report
Definition MediaCurl.cc:181
curl_off_t _dnlTotal
Bytes to download or 0 if unknown.
Definition MediaCurl.cc:188
time_t _timeStart
Start total stats.
Definition MediaCurl.cc:183
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:200
AutoDispose<int> calling ::close
AutoDispose<FILE*> calling ::fclose
virtual void report(const UserData &userData_r=UserData())
The most generic way of sending/receiving data.
Definition Callback.h:155
callback::UserData UserData
Definition Callback.h:151
Structure holding values of curlrc options.
Definition curlconfig.h:27
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
virtual void finish(const Url &, Error, const std::string &)
virtual bool progress(int, const Url &, double dbps_avg=-1, double dbps_current=-1)
Download progress.
virtual void start(const Url &, Pathname)
virtual Action problem(const Url &, Error, const std::string &)
Convenient building of std::string with boost::format.
Definition String.h:253
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition Exception.h:444
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:424
#define _(MSG)
Definition Gettext.h:39
#define DBG
Definition Logger.h:97
#define MIL
Definition Logger.h:98
#define ERR
Definition Logger.h:100
#define WAR
Definition Logger.h:99
Interface to gettext.