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