libzypp  17.27.0
MediaCurl.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
13 #include <iostream>
14 #include <list>
15 
16 #include <zypp/base/Logger.h>
17 #include <zypp/ExternalProgram.h>
18 #include <zypp/base/String.h>
19 #include <zypp/base/Gettext.h>
20 #include <zypp/base/Sysconfig.h>
21 #include <zypp/base/Gettext.h>
22 
23 #include <zypp/media/MediaCurl.h>
24 #include <zypp/media/ProxyInfo.h>
27 #include <zypp/media/CurlConfig.h>
28 #include <zypp/media/CurlHelper.h>
29 #include <zypp/Target.h>
30 #include <zypp/ZYppFactory.h>
31 #include <zypp/ZConfig.h>
32 
33 #include <cstdlib>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/mount.h>
37 #include <errno.h>
38 #include <dirent.h>
39 #include <unistd.h>
40 
41 using std::endl;
42 
43 using namespace internal;
44 using namespace zypp::base;
45 
46 namespace zypp {
47 
48  namespace media {
49 
50  namespace {
51  struct ProgressData
52  {
53  ProgressData( CURL *_curl, time_t _timeout = 0, const Url & _url = Url(),
54  ByteCount expectedFileSize_r = 0,
55  callback::SendReport<DownloadProgressReport> *_report = nullptr )
56  : curl( _curl )
57  , url( _url )
58  , timeout( _timeout )
59  , reached( false )
60  , fileSizeExceeded ( false )
61  , report( _report )
62  , _expectedFileSize( expectedFileSize_r )
63  {}
64 
65  CURL *curl;
66  Url url;
67  time_t timeout;
68  bool reached;
70  callback::SendReport<DownloadProgressReport> *report;
71  ByteCount _expectedFileSize;
72 
73  time_t _timeStart = 0;
74  time_t _timeLast = 0;
75  time_t _timeRcv = 0;
76  time_t _timeNow = 0;
77 
78  double _dnlTotal = 0.0;
79  double _dnlLast = 0.0;
80  double _dnlNow = 0.0;
81 
82  int _dnlPercent= 0;
83 
84  double _drateTotal= 0.0;
85  double _drateLast = 0.0;
86 
87  void updateStats( double dltotal = 0.0, double dlnow = 0.0 )
88  {
89  time_t now = _timeNow = time(0);
90 
91  // If called without args (0.0), recompute based on the last values seen
92  if ( dltotal && dltotal != _dnlTotal )
93  _dnlTotal = dltotal;
94 
95  if ( dlnow && dlnow != _dnlNow )
96  {
97  _timeRcv = now;
98  _dnlNow = dlnow;
99  }
100  else if ( !_dnlNow && !_dnlTotal )
101  {
102  // Start time counting as soon as first data arrives.
103  // Skip the connection / redirection time at begin.
104  return;
105  }
106 
107  // init or reset if time jumps back
108  if ( !_timeStart || _timeStart > now )
109  _timeStart = _timeLast = _timeRcv = now;
110 
111  // timeout condition
112  if ( timeout )
113  reached = ( (now - _timeRcv) > timeout );
114 
115  // check if the downloaded data is already bigger than what we expected
116  fileSizeExceeded = _expectedFileSize > 0 && _expectedFileSize < static_cast<ByteCount::SizeType>(_dnlNow);
117 
118  // percentage:
119  if ( _dnlTotal )
120  _dnlPercent = int(_dnlNow * 100 / _dnlTotal);
121 
122  // download rates:
123  _drateTotal = _dnlNow / std::max( int(now - _timeStart), 1 );
124 
125  if ( _timeLast < now )
126  {
127  _drateLast = (_dnlNow - _dnlLast) / int(now - _timeLast);
128  // start new period
129  _timeLast = now;
130  _dnlLast = _dnlNow;
131  }
132  else if ( _timeStart == _timeLast )
134  }
135 
136  int reportProgress() const
137  {
138  if ( fileSizeExceeded )
139  return 1;
140  if ( reached )
141  return 1; // no-data timeout
142  if ( report && !(*report)->progress( _dnlPercent, url, _drateTotal, _drateLast ) )
143  return 1; // user requested abort
144  return 0;
145  }
146 
147 
148  // download rate of the last period (cca 1 sec)
149  double drate_period;
150  // bytes downloaded at the start of the last period
151  double dload_period;
152  // seconds from the start of the download
153  long secs;
154  // average download rate
155  double drate_avg;
156  // last time the progress was reported
157  time_t ltime;
158  // bytes downloaded at the moment the progress was last reported
159  double dload;
160  // bytes uploaded at the moment the progress was last reported
161  double uload;
162  };
163  }
164 
165 Pathname MediaCurl::_cookieFile = "/var/lib/YaST2/cookies";
166 
167 // we use this define to unbloat code as this C setting option
168 // and catching exception is done frequently.
170 #define SET_OPTION(opt,val) do { \
171  ret = curl_easy_setopt ( _curl, opt, val ); \
172  if ( ret != 0) { \
173  ZYPP_THROW(MediaCurlSetOptException(_url, _curlError)); \
174  } \
175  } while ( false )
176 
177 #define SET_OPTION_OFFT(opt,val) SET_OPTION(opt,(curl_off_t)val)
178 #define SET_OPTION_LONG(opt,val) SET_OPTION(opt,(long)val)
179 #define SET_OPTION_VOID(opt,val) SET_OPTION(opt,(void*)val)
180 
181 MediaCurl::MediaCurl( const Url & url_r,
182  const Pathname & attach_point_hint_r )
183  : MediaHandler( url_r, attach_point_hint_r,
184  "/", // urlpath at attachpoint
185  true ), // does_download
186  _curl( NULL ),
187  _customHeaders(0L)
188 {
189  _curlError[0] = '\0';
190  _curlDebug = 0L;
191 
192  MIL << "MediaCurl::MediaCurl(" << url_r << ", " << attach_point_hint_r << ")" << endl;
193 
195 
196  if( !attachPoint().empty())
197  {
198  PathInfo ainfo(attachPoint());
199  Pathname apath(attachPoint() + "XXXXXX");
200  char *atemp = ::strdup( apath.asString().c_str());
201  char *atest = NULL;
202  if( !ainfo.isDir() || !ainfo.userMayRWX() ||
203  atemp == NULL || (atest=::mkdtemp(atemp)) == NULL)
204  {
205  WAR << "attach point " << ainfo.path()
206  << " is not useable for " << url_r.getScheme() << endl;
207  setAttachPoint("", true);
208  }
209  else if( atest != NULL)
210  ::rmdir(atest);
211 
212  if( atemp != NULL)
213  ::free(atemp);
214  }
215 }
216 
218 {
220 }
221 
223 {
224  return _settings;
225 }
226 
227 
228 void MediaCurl::setCookieFile( const Pathname &fileName )
229 {
230  _cookieFile = fileName;
231 }
232 
234 
235 void MediaCurl::checkProtocol(const Url &url) const
236 {
237  curl_version_info_data *curl_info = NULL;
238  curl_info = curl_version_info(CURLVERSION_NOW);
239  // curl_info does not need any free (is static)
240  if (curl_info->protocols)
241  {
242  const char * const *proto;
243  std::string scheme( url.getScheme());
244  bool found = false;
245  for(proto=curl_info->protocols; !found && *proto; ++proto)
246  {
247  if( scheme == std::string((const char *)*proto))
248  found = true;
249  }
250  if( !found)
251  {
252  std::string msg("Unsupported protocol '");
253  msg += scheme;
254  msg += "'";
256  }
257  }
258 }
259 
261 {
262  {
263  char *ptr = getenv("ZYPP_MEDIA_CURL_DEBUG");
264  _curlDebug = (ptr && *ptr) ? str::strtonum<long>( ptr) : 0L;
265  if( _curlDebug > 0)
266  {
267  curl_easy_setopt( _curl, CURLOPT_VERBOSE, 1L);
268  curl_easy_setopt( _curl, CURLOPT_DEBUGFUNCTION, log_curl);
269  curl_easy_setopt( _curl, CURLOPT_DEBUGDATA, &_curlDebug);
270  }
271  }
272 
273  curl_easy_setopt(_curl, CURLOPT_HEADERFUNCTION, log_redirects_curl);
274  curl_easy_setopt(_curl, CURLOPT_HEADERDATA, &_lastRedirect);
275  CURLcode ret = curl_easy_setopt( _curl, CURLOPT_ERRORBUFFER, _curlError );
276  if ( ret != 0 ) {
277  ZYPP_THROW(MediaCurlSetOptException(_url, "Error setting error buffer"));
278  }
279 
280  SET_OPTION(CURLOPT_FAILONERROR, 1L);
281  SET_OPTION(CURLOPT_NOSIGNAL, 1L);
282 
283  // create non persistant settings
284  // so that we don't add headers twice
285  TransferSettings vol_settings(_settings);
286 
287  // add custom headers for download.opensuse.org (bsc#955801)
288  if ( _url.getHost() == "download.opensuse.org" )
289  {
290  vol_settings.addHeader(anonymousIdHeader());
291  vol_settings.addHeader(distributionFlavorHeader());
292  }
293  vol_settings.addHeader("Pragma:");
294 
295  _settings.setTimeout(ZConfig::instance().download_transfer_timeout());
297 
299 
300  // fill some settings from url query parameters
301  try
302  {
304  }
305  catch ( const MediaException &e )
306  {
307  disconnectFrom();
308  ZYPP_RETHROW(e);
309  }
310  // if the proxy was not set (or explicitly unset) by url, then look...
311  if ( _settings.proxy().empty() )
312  {
313  // ...at the system proxy settings
315  }
316 
319  {
320  switch ( env::ZYPP_MEDIA_CURL_IPRESOLVE() )
321  {
322  case 4: SET_OPTION(CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); break;
323  case 6: SET_OPTION(CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); break;
324  }
325  }
326 
330  SET_OPTION(CURLOPT_CONNECTTIMEOUT, _settings.connectTimeout());
331  // If a transfer timeout is set, also set CURLOPT_TIMEOUT to an upper limit
332  // just in case curl does not trigger its progress callback frequently
333  // enough.
334  if ( _settings.timeout() )
335  {
336  SET_OPTION(CURLOPT_TIMEOUT, 3600L);
337  }
338 
339  // follow any Location: header that the server sends as part of
340  // an HTTP header (#113275)
341  SET_OPTION(CURLOPT_FOLLOWLOCATION, 1L);
342  // 3 redirects seem to be too few in some cases (bnc #465532)
343  SET_OPTION(CURLOPT_MAXREDIRS, 6L);
344 
345  if ( _url.getScheme() == "https" )
346  {
347 #if CURLVERSION_AT_LEAST(7,19,4)
348  // restrict following of redirections from https to https only
349  if ( _url.getHost() == "download.opensuse.org" )
350  SET_OPTION( CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS );
351  else
352  SET_OPTION( CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS );
353 #endif
354 
357  {
359  }
360 
362  {
363  SET_OPTION(CURLOPT_SSLCERT, _settings.clientCertificatePath().c_str());
364  }
365  if( ! _settings.clientKeyPath().empty() )
366  {
367  SET_OPTION(CURLOPT_SSLKEY, _settings.clientKeyPath().c_str());
368  }
369 
370 #ifdef CURLSSLOPT_ALLOW_BEAST
371  // see bnc#779177
372  ret = curl_easy_setopt( _curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_ALLOW_BEAST );
373  if ( ret != 0 ) {
374  disconnectFrom();
376  }
377 #endif
378  SET_OPTION(CURLOPT_SSL_VERIFYPEER, _settings.verifyPeerEnabled() ? 1L : 0L);
379  SET_OPTION(CURLOPT_SSL_VERIFYHOST, _settings.verifyHostEnabled() ? 2L : 0L);
380  // bnc#903405 - POODLE: libzypp should only talk TLS
381  SET_OPTION(CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
382  }
383 
384  SET_OPTION(CURLOPT_USERAGENT, _settings.userAgentString().c_str() );
385 
386  /* Fixes bsc#1174011 "auth=basic ignored in some cases"
387  * We should proactively add the password to the request if basic auth is configured
388  * and a password is available in the credentials but not in the URL.
389  *
390  * We will be a bit paranoid here and require that the URL has a user embedded, otherwise we go the default route
391  * and ask the server first about the auth method
392  */
393  if ( _settings.authType() == "basic"
394  && _settings.username().size()
395  && !_settings.password().size() ) {
396 
397  CredentialManager cm(CredManagerOptions(ZConfig::instance().repoManagerRoot()));
398  const auto cred = cm.getCred( _url );
399  if ( cred && cred->valid() ) {
400  if ( !_settings.username().size() )
401  _settings.setUsername(cred->username());
402  _settings.setPassword(cred->password());
403  }
404  }
405 
406  /*---------------------------------------------------------------*
407  CURLOPT_USERPWD: [user name]:[password]
408 
409  Url::username/password -> CURLOPT_USERPWD
410  If not provided, anonymous FTP identification
411  *---------------------------------------------------------------*/
412 
413  if ( _settings.userPassword().size() )
414  {
415  SET_OPTION(CURLOPT_USERPWD, _settings.userPassword().c_str());
416  std::string use_auth = _settings.authType();
417  if (use_auth.empty())
418  use_auth = "digest,basic"; // our default
419  long auth = CurlAuthData::auth_type_str2long(use_auth);
420  if( auth != CURLAUTH_NONE)
421  {
422  DBG << "Enabling HTTP authentication methods: " << use_auth
423  << " (CURLOPT_HTTPAUTH=" << auth << ")" << std::endl;
424  SET_OPTION(CURLOPT_HTTPAUTH, auth);
425  }
426  }
427 
428  if ( _settings.proxyEnabled() && ! _settings.proxy().empty() )
429  {
430  DBG << "Proxy: '" << _settings.proxy() << "'" << endl;
431  SET_OPTION(CURLOPT_PROXY, _settings.proxy().c_str());
432  SET_OPTION(CURLOPT_PROXYAUTH, CURLAUTH_BASIC|CURLAUTH_DIGEST|CURLAUTH_NTLM );
433  /*---------------------------------------------------------------*
434  * CURLOPT_PROXYUSERPWD: [user name]:[password]
435  *
436  * Url::option(proxyuser and proxypassword) -> CURLOPT_PROXYUSERPWD
437  * If not provided, $HOME/.curlrc is evaluated
438  *---------------------------------------------------------------*/
439 
440  std::string proxyuserpwd = _settings.proxyUserPassword();
441 
442  if ( proxyuserpwd.empty() )
443  {
444  CurlConfig curlconf;
445  CurlConfig::parseConfig(curlconf); // parse ~/.curlrc
446  if ( curlconf.proxyuserpwd.empty() )
447  DBG << "Proxy: ~/.curlrc does not contain the proxy-user option" << endl;
448  else
449  {
450  proxyuserpwd = curlconf.proxyuserpwd;
451  DBG << "Proxy: using proxy-user from ~/.curlrc" << endl;
452  }
453  }
454  else
455  {
456  DBG << "Proxy: using provided proxy-user '" << _settings.proxyUsername() << "'" << endl;
457  }
458 
459  if ( ! proxyuserpwd.empty() )
460  {
461  SET_OPTION(CURLOPT_PROXYUSERPWD, curlUnEscape( proxyuserpwd ).c_str());
462  }
463  }
464 #if CURLVERSION_AT_LEAST(7,19,4)
465  else if ( _settings.proxy() == EXPLICITLY_NO_PROXY )
466  {
467  // Explicitly disabled in URL (see fillSettingsFromUrl()).
468  // This should also prevent libcurl from looking into the environment.
469  DBG << "Proxy: explicitly NOPROXY" << endl;
470  SET_OPTION(CURLOPT_NOPROXY, "*");
471  }
472 #endif
473  else
474  {
475  DBG << "Proxy: not explicitly set" << endl;
476  DBG << "Proxy: libcurl may look into the environment" << endl;
477  }
478 
480  if ( _settings.minDownloadSpeed() != 0 )
481  {
482  SET_OPTION(CURLOPT_LOW_SPEED_LIMIT, _settings.minDownloadSpeed());
483  // default to 10 seconds at low speed
484  SET_OPTION(CURLOPT_LOW_SPEED_TIME, 60L);
485  }
486 
487 #if CURLVERSION_AT_LEAST(7,15,5)
488  if ( _settings.maxDownloadSpeed() != 0 )
489  SET_OPTION_OFFT(CURLOPT_MAX_RECV_SPEED_LARGE, _settings.maxDownloadSpeed());
490 #endif
491 
492  /*---------------------------------------------------------------*
493  *---------------------------------------------------------------*/
494 
497  if ( str::strToBool( _url.getQueryParam( "cookies" ), true ) )
498  SET_OPTION(CURLOPT_COOKIEFILE, _currentCookieFile.c_str() );
499  else
500  MIL << "No cookies requested" << endl;
501  SET_OPTION(CURLOPT_COOKIEJAR, _currentCookieFile.c_str() );
502  SET_OPTION(CURLOPT_PROGRESSFUNCTION, &progressCallback );
503  SET_OPTION(CURLOPT_NOPROGRESS, 0L);
504 
505 #if CURLVERSION_AT_LEAST(7,18,0)
506  // bnc #306272
507  SET_OPTION(CURLOPT_PROXY_TRANSFER_MODE, 1L );
508 #endif
509  // append settings custom headers to curl
510  for ( TransferSettings::Headers::const_iterator it = vol_settings.headersBegin();
511  it != vol_settings.headersEnd();
512  ++it )
513  {
514  // MIL << "HEADER " << *it << std::endl;
515 
516  _customHeaders = curl_slist_append(_customHeaders, it->c_str());
517  if ( !_customHeaders )
519  }
520 
521  SET_OPTION(CURLOPT_HTTPHEADER, _customHeaders);
522 }
523 
525 
526 
527 void MediaCurl::attachTo (bool next)
528 {
529  if ( next )
531 
532  if ( !_url.isValid() )
534 
537  {
539  }
540 
541  disconnectFrom(); // clean _curl if needed
542  _curl = curl_easy_init();
543  if ( !_curl ) {
545  }
546  try
547  {
548  setupEasy();
549  }
550  catch (Exception & ex)
551  {
552  disconnectFrom();
553  ZYPP_RETHROW(ex);
554  }
555 
556  // FIXME: need a derived class to propelly compare url's
558  setMediaSource(media);
559 }
560 
561 bool
563 {
564  return MediaHandler::checkAttachPoint( apoint, true, true);
565 }
566 
568 
570 {
571  if ( _customHeaders )
572  {
573  curl_slist_free_all(_customHeaders);
574  _customHeaders = 0L;
575  }
576 
577  if ( _curl )
578  {
579  curl_easy_cleanup( _curl );
580  _curl = NULL;
581  }
582 }
583 
585 
586 void MediaCurl::releaseFrom( const std::string & ejectDev )
587 {
588  disconnect();
589 }
590 
591 Url MediaCurl::getFileUrl( const Pathname & filename_r ) const
592 {
593  // Simply extend the URLs pathname. An 'absolute' URL path
594  // is achieved by encoding the leading '/' in an URL path:
595  // URL: ftp://user@server -> ~user
596  // URL: ftp://user@server/ -> ~user
597  // URL: ftp://user@server// -> ~user
598  // URL: ftp://user@server/%2F -> /
599  // ^- this '/' is just a separator
600  Url newurl( _url );
601  newurl.setPathName( ( Pathname("./"+_url.getPathName()) / filename_r ).asString().substr(1) );
602  return newurl;
603 }
604 
606 
607 void MediaCurl::getFile(const Pathname & filename , const ByteCount &expectedFileSize_r) const
608 {
609  // Use absolute file name to prevent access of files outside of the
610  // hierarchy below the attach point.
611  getFileCopy(filename, localPath(filename).absolutename(), expectedFileSize_r);
612 }
613 
615 
616 void MediaCurl::getFileCopy( const Pathname & filename , const Pathname & target, const ByteCount &expectedFileSize_r ) const
617 {
619 
620  Url fileurl(getFileUrl(filename));
621 
622  bool retry = false;
623 
624  do
625  {
626  try
627  {
628  doGetFileCopy(filename, target, report, expectedFileSize_r);
629  retry = false;
630  }
631  // retry with proper authentication data
632  catch (MediaUnauthorizedException & ex_r)
633  {
634  if(authenticate(ex_r.hint(), !retry))
635  retry = true;
636  else
637  {
639  ZYPP_RETHROW(ex_r);
640  }
641  }
642  // unexpected exception
643  catch (MediaException & excpt_r)
644  {
646  if( typeid(excpt_r) == typeid( media::MediaFileNotFoundException ) ||
647  typeid(excpt_r) == typeid( media::MediaNotAFileException ) )
648  {
650  }
651  report->finish(fileurl, reason, excpt_r.asUserHistory());
652  ZYPP_RETHROW(excpt_r);
653  }
654  }
655  while (retry);
656 
658 }
659 
661 
662 bool MediaCurl::getDoesFileExist( const Pathname & filename ) const
663 {
664  bool retry = false;
665 
666  do
667  {
668  try
669  {
670  return doGetDoesFileExist( filename );
671  }
672  // authentication problem, retry with proper authentication data
673  catch (MediaUnauthorizedException & ex_r)
674  {
675  if(authenticate(ex_r.hint(), !retry))
676  retry = true;
677  else
678  ZYPP_RETHROW(ex_r);
679  }
680  // unexpected exception
681  catch (MediaException & excpt_r)
682  {
683  ZYPP_RETHROW(excpt_r);
684  }
685  }
686  while (retry);
687 
688  return false;
689 }
690 
692 
694  CURLcode code,
695  bool timeout_reached) const
696 {
697  if ( code != 0 )
698  {
699  Url url;
700  if (filename.empty())
701  url = _url;
702  else
703  url = getFileUrl(filename);
704 
705  std::string err;
706  {
707  switch ( code )
708  {
709  case CURLE_UNSUPPORTED_PROTOCOL:
710  err = " Unsupported protocol";
711  if ( !_lastRedirect.empty() )
712  {
713  err += " or redirect (";
714  err += _lastRedirect;
715  err += ")";
716  }
717  break;
718  case CURLE_URL_MALFORMAT:
719  case CURLE_URL_MALFORMAT_USER:
720  err = " Bad URL";
721  break;
722  case CURLE_LOGIN_DENIED:
723  ZYPP_THROW(
724  MediaUnauthorizedException(url, "Login failed.", _curlError, ""));
725  break;
726  case CURLE_HTTP_RETURNED_ERROR:
727  {
728  long httpReturnCode = 0;
729  CURLcode infoRet = curl_easy_getinfo( _curl,
730  CURLINFO_RESPONSE_CODE,
731  &httpReturnCode );
732  if ( infoRet == CURLE_OK )
733  {
734  std::string msg = "HTTP response: " + str::numstring( httpReturnCode );
735  switch ( httpReturnCode )
736  {
737  case 401:
738  {
739  std::string auth_hint = getAuthHint();
740 
741  DBG << msg << " Login failed (URL: " << url.asString() << ")" << std::endl;
742  DBG << "MediaUnauthorizedException auth hint: '" << auth_hint << "'" << std::endl;
743 
745  url, "Login failed.", _curlError, auth_hint
746  ));
747  }
748 
749  case 502: // bad gateway (bnc #1070851)
750  case 503: // service temporarily unavailable (bnc #462545)
752  case 504: // gateway timeout
754  case 403:
755  {
756  std::string msg403;
757  if ( url.getHost().find(".suse.com") != std::string::npos )
758  msg403 = _("Visit the SUSE Customer Center to check whether your registration is valid and has not expired.");
759  else if (url.asString().find("novell.com") != std::string::npos)
760  msg403 = _("Visit the Novell Customer Center to check whether your registration is valid and has not expired.");
762  }
763  case 404:
764  case 410:
766  }
767 
768  DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
770  }
771  else
772  {
773  std::string msg = "Unable to retrieve HTTP response:";
774  DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
776  }
777  }
778  break;
779  case CURLE_FTP_COULDNT_RETR_FILE:
780 #if CURLVERSION_AT_LEAST(7,16,0)
781  case CURLE_REMOTE_FILE_NOT_FOUND:
782 #endif
783  case CURLE_FTP_ACCESS_DENIED:
784  case CURLE_TFTP_NOTFOUND:
785  err = "File not found";
787  break;
788  case CURLE_BAD_PASSWORD_ENTERED:
789  case CURLE_FTP_USER_PASSWORD_INCORRECT:
790  err = "Login failed";
791  break;
792  case CURLE_COULDNT_RESOLVE_PROXY:
793  case CURLE_COULDNT_RESOLVE_HOST:
794  case CURLE_COULDNT_CONNECT:
795  case CURLE_FTP_CANT_GET_HOST:
796  err = "Connection failed";
797  break;
798  case CURLE_WRITE_ERROR:
799  err = "Write error";
800  break;
801  case CURLE_PARTIAL_FILE:
802  case CURLE_OPERATION_TIMEDOUT:
803  timeout_reached = true; // fall though to TimeoutException
804  // fall though...
805  case CURLE_ABORTED_BY_CALLBACK:
806  if( timeout_reached )
807  {
808  err = "Timeout reached";
810  }
811  else
812  {
813  err = "User abort";
814  }
815  break;
816  case CURLE_SSL_PEER_CERTIFICATE:
817  default:
818  err = "Curl error " + str::numstring( code );
819  break;
820  }
821 
822  // uhm, no 0 code but unknown curl exception
824  }
825  }
826  else
827  {
828  // actually the code is 0, nothing happened
829  }
830 }
831 
833 
834 bool MediaCurl::doGetDoesFileExist( const Pathname & filename ) const
835 {
836  DBG << filename.asString() << endl;
837 
838  if(!_url.isValid())
840 
841  if(_url.getHost().empty())
843 
844  Url url(getFileUrl(filename));
845 
846  DBG << "URL: " << url.asString() << endl;
847  // Use URL without options and without username and passwd
848  // (some proxies dislike them in the URL).
849  // Curl seems to need the just scheme, hostname and a path;
850  // the rest was already passed as curl options (in attachTo).
851  Url curlUrl( clearQueryString(url) );
852 
853  //
854  // See also Bug #154197 and ftp url definition in RFC 1738:
855  // The url "ftp://user@host/foo/bar/file" contains a path,
856  // that is relative to the user's home.
857  // The url "ftp://user@host//foo/bar/file" (or also with
858  // encoded slash as %2f) "ftp://user@host/%2ffoo/bar/file"
859  // contains an absolute path.
860  //
861  _lastRedirect.clear();
862  std::string urlBuffer( curlUrl.asString());
863  CURLcode ret = curl_easy_setopt( _curl, CURLOPT_URL,
864  urlBuffer.c_str() );
865  if ( ret != 0 ) {
867  }
868 
869  // instead of returning no data with NOBODY, we return
870  // little data, that works with broken servers, and
871  // works for ftp as well, because retrieving only headers
872  // ftp will return always OK code ?
873  // See http://curl.haxx.se/docs/knownbugs.html #58
874  if ( (_url.getScheme() == "http" || _url.getScheme() == "https") &&
876  ret = curl_easy_setopt( _curl, CURLOPT_NOBODY, 1L );
877  else
878  ret = curl_easy_setopt( _curl, CURLOPT_RANGE, "0-1" );
879 
880  if ( ret != 0 ) {
881  curl_easy_setopt( _curl, CURLOPT_NOBODY, 0L);
882  curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
883  /* yes, this is why we never got to get NOBODY working before,
884  because setting it changes this option too, and we also
885  need to reset it
886  See: http://curl.haxx.se/mail/archive-2005-07/0073.html
887  */
888  curl_easy_setopt( _curl, CURLOPT_HTTPGET, 1L );
890  }
891 
892  AutoFILE file { ::fopen( "/dev/null", "w" ) };
893  if ( !file ) {
894  ERR << "fopen failed for /dev/null" << endl;
895  curl_easy_setopt( _curl, CURLOPT_NOBODY, 0L);
896  curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
897  /* yes, this is why we never got to get NOBODY working before,
898  because setting it changes this option too, and we also
899  need to reset it
900  See: http://curl.haxx.se/mail/archive-2005-07/0073.html
901  */
902  curl_easy_setopt( _curl, CURLOPT_HTTPGET, 1L );
903  if ( ret != 0 ) {
905  }
906  ZYPP_THROW(MediaWriteException("/dev/null"));
907  }
908 
909  ret = curl_easy_setopt( _curl, CURLOPT_WRITEDATA, (*file) );
910  if ( ret != 0 ) {
911  std::string err( _curlError);
912  curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
913  curl_easy_setopt( _curl, CURLOPT_NOBODY, 0L);
914  /* yes, this is why we never got to get NOBODY working before,
915  because setting it changes this option too, and we also
916  need to reset it
917  See: http://curl.haxx.se/mail/archive-2005-07/0073.html
918  */
919  curl_easy_setopt( _curl, CURLOPT_HTTPGET, 1L );
920  if ( ret != 0 ) {
922  }
924  }
925 
926  CURLcode ok = curl_easy_perform( _curl );
927  MIL << "perform code: " << ok << " [ " << curl_easy_strerror(ok) << " ]" << endl;
928 
929  // reset curl settings
930  if ( _url.getScheme() == "http" || _url.getScheme() == "https" )
931  {
932  curl_easy_setopt( _curl, CURLOPT_NOBODY, 0L);
933  if ( ret != 0 ) {
935  }
936 
937  /* yes, this is why we never got to get NOBODY working before,
938  because setting it changes this option too, and we also
939  need to reset it
940  See: http://curl.haxx.se/mail/archive-2005-07/0073.html
941  */
942  curl_easy_setopt( _curl, CURLOPT_HTTPGET, 1L);
943  if ( ret != 0 ) {
945  }
946 
947  }
948  else
949  {
950  // for FTP we set different options
951  curl_easy_setopt( _curl, CURLOPT_RANGE, NULL);
952  if ( ret != 0 ) {
954  }
955  }
956 
957  // as we are not having user interaction, the user can't cancel
958  // the file existence checking, a callback or timeout return code
959  // will be always a timeout.
960  try {
961  evaluateCurlCode( filename, ok, true /* timeout */);
962  }
963  catch ( const MediaFileNotFoundException &e ) {
964  // if the file did not exist then we can return false
965  return false;
966  }
967  catch ( const MediaException &e ) {
968  // some error, we are not sure about file existence, rethrw
969  ZYPP_RETHROW(e);
970  }
971  // exists
972  return ( ok == CURLE_OK );
973 }
974 
976 
977 
978 #if DETECT_DIR_INDEX
979 bool MediaCurl::detectDirIndex() const
980 {
981  if(_url.getScheme() != "http" && _url.getScheme() != "https")
982  return false;
983  //
984  // try to check the effective url and set the not_a_file flag
985  // if the url path ends with a "/", what usually means, that
986  // we've received a directory index (index.html content).
987  //
988  // Note: This may be dangerous and break file retrieving in
989  // case of some server redirections ... ?
990  //
991  bool not_a_file = false;
992  char *ptr = NULL;
993  CURLcode ret = curl_easy_getinfo( _curl,
994  CURLINFO_EFFECTIVE_URL,
995  &ptr);
996  if ( ret == CURLE_OK && ptr != NULL)
997  {
998  try
999  {
1000  Url eurl( ptr);
1001  std::string path( eurl.getPathName());
1002  if( !path.empty() && path != "/" && *path.rbegin() == '/')
1003  {
1004  DBG << "Effective url ("
1005  << eurl
1006  << ") seems to provide the index of a directory"
1007  << endl;
1008  not_a_file = true;
1009  }
1010  }
1011  catch( ... )
1012  {}
1013  }
1014  return not_a_file;
1015 }
1016 #endif
1017 
1019 
1020 void MediaCurl::doGetFileCopy(const Pathname & filename , const Pathname & target, callback::SendReport<DownloadProgressReport> & report, const ByteCount &expectedFileSize_r, RequestOptions options ) const
1021 {
1022  Pathname dest = target.absolutename();
1023  if( assert_dir( dest.dirname() ) )
1024  {
1025  DBG << "assert_dir " << dest.dirname() << " failed" << endl;
1026  ZYPP_THROW( MediaSystemException(getFileUrl(filename), "System error on " + dest.dirname().asString()) );
1027  }
1028 
1029  ManagedFile destNew { target.extend( ".new.zypp.XXXXXX" ) };
1030  AutoFILE file;
1031  {
1032  AutoFREE<char> buf { ::strdup( (*destNew).c_str() ) };
1033  if( ! buf )
1034  {
1035  ERR << "out of memory for temp file name" << endl;
1036  ZYPP_THROW(MediaSystemException(getFileUrl(filename), "out of memory for temp file name"));
1037  }
1038 
1039  AutoFD tmp_fd { ::mkostemp( buf, O_CLOEXEC ) };
1040  if( tmp_fd == -1 )
1041  {
1042  ERR << "mkstemp failed for file '" << destNew << "'" << endl;
1043  ZYPP_THROW(MediaWriteException(destNew));
1044  }
1045  destNew = ManagedFile( (*buf), filesystem::unlink );
1046 
1047  file = ::fdopen( tmp_fd, "we" );
1048  if ( ! file )
1049  {
1050  ERR << "fopen failed for file '" << destNew << "'" << endl;
1051  ZYPP_THROW(MediaWriteException(destNew));
1052  }
1053  tmp_fd.resetDispose(); // don't close it here! ::fdopen moved ownership to file
1054  }
1055 
1056  DBG << "dest: " << dest << endl;
1057  DBG << "temp: " << destNew << endl;
1058 
1059  // set IFMODSINCE time condition (no download if not modified)
1060  if( PathInfo(target).isExist() && !(options & OPTION_NO_IFMODSINCE) )
1061  {
1062  curl_easy_setopt(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
1063  curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, (long)PathInfo(target).mtime());
1064  }
1065  else
1066  {
1067  curl_easy_setopt(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
1068  curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, 0L);
1069  }
1070  try
1071  {
1072  doGetFileCopyFile(filename, dest, file, report, expectedFileSize_r, options);
1073  }
1074  catch (Exception &e)
1075  {
1076  curl_easy_setopt(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
1077  curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, 0L);
1078  ZYPP_RETHROW(e);
1079  }
1080 
1081  long httpReturnCode = 0;
1082  CURLcode infoRet = curl_easy_getinfo(_curl,
1083  CURLINFO_RESPONSE_CODE,
1084  &httpReturnCode);
1085  bool modified = true;
1086  if (infoRet == CURLE_OK)
1087  {
1088  DBG << "HTTP response: " + str::numstring(httpReturnCode);
1089  if ( httpReturnCode == 304
1090  || ( httpReturnCode == 213 && (_url.getScheme() == "ftp" || _url.getScheme() == "tftp") ) ) // not modified
1091  {
1092  DBG << " Not modified.";
1093  modified = false;
1094  }
1095  DBG << endl;
1096  }
1097  else
1098  {
1099  WAR << "Could not get the reponse code." << endl;
1100  }
1101 
1102  if (modified || infoRet != CURLE_OK)
1103  {
1104  // apply umask
1105  if ( ::fchmod( ::fileno(file), filesystem::applyUmaskTo( 0644 ) ) )
1106  {
1107  ERR << "Failed to chmod file " << destNew << endl;
1108  }
1109 
1110  file.resetDispose(); // we're going to close it manually here
1111  if ( ::fclose( file ) )
1112  {
1113  ERR << "Fclose failed for file '" << destNew << "'" << endl;
1114  ZYPP_THROW(MediaWriteException(destNew));
1115  }
1116 
1117  // move the temp file into dest
1118  if ( rename( destNew, dest ) != 0 ) {
1119  ERR << "Rename failed" << endl;
1121  }
1122  destNew.resetDispose(); // no more need to unlink it
1123  }
1124 
1125  DBG << "done: " << PathInfo(dest) << endl;
1126 }
1127 
1129 
1130 void MediaCurl::doGetFileCopyFile(const Pathname & filename , const Pathname & dest, FILE *file, callback::SendReport<DownloadProgressReport> & report, const ByteCount &expectedFileSize_r, RequestOptions options ) const
1131 {
1132  DBG << filename.asString() << endl;
1133 
1134  if(!_url.isValid())
1136 
1137  if(_url.getHost().empty())
1139 
1140  Url url(getFileUrl(filename));
1141 
1142  DBG << "URL: " << url.asString() << endl;
1143  // Use URL without options and without username and passwd
1144  // (some proxies dislike them in the URL).
1145  // Curl seems to need the just scheme, hostname and a path;
1146  // the rest was already passed as curl options (in attachTo).
1147  Url curlUrl( clearQueryString(url) );
1148 
1149  //
1150  // See also Bug #154197 and ftp url definition in RFC 1738:
1151  // The url "ftp://user@host/foo/bar/file" contains a path,
1152  // that is relative to the user's home.
1153  // The url "ftp://user@host//foo/bar/file" (or also with
1154  // encoded slash as %2f) "ftp://user@host/%2ffoo/bar/file"
1155  // contains an absolute path.
1156  //
1157  _lastRedirect.clear();
1158  std::string urlBuffer( curlUrl.asString());
1159  CURLcode ret = curl_easy_setopt( _curl, CURLOPT_URL,
1160  urlBuffer.c_str() );
1161  if ( ret != 0 ) {
1163  }
1164 
1165  ret = curl_easy_setopt( _curl, CURLOPT_WRITEDATA, file );
1166  if ( ret != 0 ) {
1168  }
1169 
1170  // Set callback and perform.
1171  ProgressData progressData(_curl, _settings.timeout(), url, expectedFileSize_r, &report);
1172  if (!(options & OPTION_NO_REPORT_START))
1173  report->start(url, dest);
1174  if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, &progressData ) != 0 ) {
1175  WAR << "Can't set CURLOPT_PROGRESSDATA: " << _curlError << endl;;
1176  }
1177 
1178  ret = curl_easy_perform( _curl );
1179 #if CURLVERSION_AT_LEAST(7,19,4)
1180  // bnc#692260: If the client sends a request with an If-Modified-Since header
1181  // with a future date for the server, the server may respond 200 sending a
1182  // zero size file.
1183  // curl-7.19.4 introduces CURLINFO_CONDITION_UNMET to check this condition.
1184  if ( ftell(file) == 0 && ret == 0 )
1185  {
1186  long httpReturnCode = 33;
1187  if ( curl_easy_getinfo( _curl, CURLINFO_RESPONSE_CODE, &httpReturnCode ) == CURLE_OK && httpReturnCode == 200 )
1188  {
1189  long conditionUnmet = 33;
1190  if ( curl_easy_getinfo( _curl, CURLINFO_CONDITION_UNMET, &conditionUnmet ) == CURLE_OK && conditionUnmet )
1191  {
1192  WAR << "TIMECONDITION unmet - retry without." << endl;
1193  curl_easy_setopt(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
1194  curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, 0L);
1195  ret = curl_easy_perform( _curl );
1196  }
1197  }
1198  }
1199 #endif
1200 
1201  if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, NULL ) != 0 ) {
1202  WAR << "Can't unset CURLOPT_PROGRESSDATA: " << _curlError << endl;;
1203  }
1204 
1205  if ( ret != 0 )
1206  {
1207  ERR << "curl error: " << ret << ": " << _curlError
1208  << ", temp file size " << ftell(file)
1209  << " bytes." << endl;
1210 
1211  // the timeout is determined by the progress data object
1212  // which holds whether the timeout was reached or not,
1213  // otherwise it would be a user cancel
1214  try {
1215 
1216  if ( progressData.fileSizeExceeded )
1217  ZYPP_THROW(MediaFileSizeExceededException(url, progressData._expectedFileSize));
1218 
1219  evaluateCurlCode( filename, ret, progressData.reached );
1220  }
1221  catch ( const MediaException &e ) {
1222  // some error, we are not sure about file existence, rethrw
1223  ZYPP_RETHROW(e);
1224  }
1225  }
1226 
1227 #if DETECT_DIR_INDEX
1228  if (!ret && detectDirIndex())
1229  {
1231  }
1232 #endif // DETECT_DIR_INDEX
1233 }
1234 
1236 
1237 void MediaCurl::getDir( const Pathname & dirname, bool recurse_r ) const
1238 {
1239  filesystem::DirContent content;
1240  getDirInfo( content, dirname, /*dots*/false );
1241 
1242  for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
1243  Pathname filename = dirname + it->name;
1244  int res = 0;
1245 
1246  switch ( it->type ) {
1247  case filesystem::FT_NOT_AVAIL: // old directory.yast contains no typeinfo at all
1248  case filesystem::FT_FILE:
1249  getFile( filename, 0 );
1250  break;
1251  case filesystem::FT_DIR: // newer directory.yast contain at least directory info
1252  if ( recurse_r ) {
1253  getDir( filename, recurse_r );
1254  } else {
1255  res = assert_dir( localPath( filename ) );
1256  if ( res ) {
1257  WAR << "Ignore error (" << res << ") on creating local directory '" << localPath( filename ) << "'" << endl;
1258  }
1259  }
1260  break;
1261  default:
1262  // don't provide devices, sockets, etc.
1263  break;
1264  }
1265  }
1266 }
1267 
1269 
1270 void MediaCurl::getDirInfo( std::list<std::string> & retlist,
1271  const Pathname & dirname, bool dots ) const
1272 {
1273  getDirectoryYast( retlist, dirname, dots );
1274 }
1275 
1277 
1279  const Pathname & dirname, bool dots ) const
1280 {
1281  getDirectoryYast( retlist, dirname, dots );
1282 }
1283 
1285 //
1286 int MediaCurl::aliveCallback( void *clientp, double /*dltotal*/, double dlnow, double /*ultotal*/, double /*ulnow*/ )
1287 {
1288  ProgressData *pdata = reinterpret_cast<ProgressData *>( clientp );
1289  if( pdata )
1290  {
1291  // Do not propagate dltotal in alive callbacks. MultiCurl uses this to
1292  // prevent a percentage raise while downloading a metalink file. Download
1293  // activity however is indicated by propagating the download rate (via dlnow).
1294  pdata->updateStats( 0.0, dlnow );
1295  return pdata->reportProgress();
1296  }
1297  return 0;
1298 }
1299 
1300 int MediaCurl::progressCallback( void *clientp, double dltotal, double dlnow, double ultotal, double ulnow )
1301 {
1302  ProgressData *pdata = reinterpret_cast<ProgressData *>( clientp );
1303  if( pdata )
1304  {
1305  // work around curl bug that gives us old data
1306  long httpReturnCode = 0;
1307  if ( curl_easy_getinfo( pdata->curl, CURLINFO_RESPONSE_CODE, &httpReturnCode ) != CURLE_OK || httpReturnCode == 0 )
1308  return aliveCallback( clientp, dltotal, dlnow, ultotal, ulnow );
1309 
1310  pdata->updateStats( dltotal, dlnow );
1311  return pdata->reportProgress();
1312  }
1313  return 0;
1314 }
1315 
1317 {
1318  ProgressData *pdata = reinterpret_cast<ProgressData *>(clientp);
1319  return pdata ? pdata->curl : 0;
1320 }
1321 
1323 
1324 std::string MediaCurl::getAuthHint() const
1325 {
1326  long auth_info = CURLAUTH_NONE;
1327 
1328  CURLcode infoRet =
1329  curl_easy_getinfo(_curl, CURLINFO_HTTPAUTH_AVAIL, &auth_info);
1330 
1331  if(infoRet == CURLE_OK)
1332  {
1333  return CurlAuthData::auth_type_long2str(auth_info);
1334  }
1335 
1336  return "";
1337 }
1338 
1343 void MediaCurl::resetExpectedFileSize(void *clientp, const ByteCount &expectedFileSize)
1344 {
1345  ProgressData *data = reinterpret_cast<ProgressData *>(clientp);
1346  if ( data ) {
1347  data->_expectedFileSize = expectedFileSize;
1348  }
1349 }
1350 
1352 
1353 bool MediaCurl::authenticate(const std::string & availAuthTypes, bool firstTry) const
1354 {
1356  CredentialManager cm(CredManagerOptions(ZConfig::instance().repoManagerRoot()));
1357  CurlAuthData_Ptr credentials;
1358 
1359  // get stored credentials
1360  AuthData_Ptr cmcred = cm.getCred(_url);
1361 
1362  if (cmcred && firstTry)
1363  {
1364  credentials.reset(new CurlAuthData(*cmcred));
1365  DBG << "got stored credentials:" << endl << *credentials << endl;
1366  }
1367  // if not found, ask user
1368  else
1369  {
1370 
1371  CurlAuthData_Ptr curlcred;
1372  curlcred.reset(new CurlAuthData());
1374 
1375  // preset the username if present in current url
1376  if (!_url.getUsername().empty() && firstTry)
1377  curlcred->setUsername(_url.getUsername());
1378  // if CM has found some credentials, preset the username from there
1379  else if (cmcred)
1380  curlcred->setUsername(cmcred->username());
1381 
1382  // indicate we have no good credentials from CM
1383  cmcred.reset();
1384 
1385  std::string prompt_msg = str::Format(_("Authentication required for '%s'")) % _url.asString();
1386 
1387  // set available authentication types from the exception
1388  // might be needed in prompt
1389  curlcred->setAuthType(availAuthTypes);
1390 
1391  // ask user
1392  if (auth_report->prompt(_url, prompt_msg, *curlcred))
1393  {
1394  DBG << "callback answer: retry" << endl
1395  << "CurlAuthData: " << *curlcred << endl;
1396 
1397  if (curlcred->valid())
1398  {
1399  credentials = curlcred;
1400  // if (credentials->username() != _url.getUsername())
1401  // _url.setUsername(credentials->username());
1409  }
1410  }
1411  else
1412  {
1413  DBG << "callback answer: cancel" << endl;
1414  }
1415  }
1416 
1417  // set username and password
1418  if (credentials)
1419  {
1420  // HACK, why is this const?
1421  const_cast<MediaCurl*>(this)->_settings.setUsername(credentials->username());
1422  const_cast<MediaCurl*>(this)->_settings.setPassword(credentials->password());
1423 
1424  // set username and password
1425  CURLcode ret = curl_easy_setopt(_curl, CURLOPT_USERPWD, _settings.userPassword().c_str());
1427 
1428  // set available authentication types from the exception
1429  if (credentials->authType() == CURLAUTH_NONE)
1430  credentials->setAuthType(availAuthTypes);
1431 
1432  // set auth type (seems this must be set _after_ setting the userpwd)
1433  if (credentials->authType() != CURLAUTH_NONE)
1434  {
1435  // FIXME: only overwrite if not empty?
1436  const_cast<MediaCurl*>(this)->_settings.setAuthType(credentials->authTypeAsString());
1437  ret = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, credentials->authType());
1439  }
1440 
1441  if (!cmcred)
1442  {
1443  credentials->setUrl(_url);
1444  cm.addCred(*credentials);
1445  cm.save();
1446  }
1447 
1448  return true;
1449  }
1450 
1451  return false;
1452 }
1453 
1454 //need a out of line definiton, otherwise vtable is emitted for every translation unit
1456 
1457 
1458  } // namespace media
1459 } // namespace zypp
1460 //
#define CONNECT_TIMEOUT
Definition: CurlHelper.h:21
#define EXPLICITLY_NO_PROXY
Definition: CurlHelper.h:25
#define ZYPP_RETHROW(EXCPT)
Drops a logline and rethrows, updating the CodeLocation.
Definition: Exception.h:400
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:392
Interface to gettext.
#define _(MSG)
Definition: Gettext.h:37
#define DBG
Definition: Logger.h:95
#define MIL
Definition: Logger.h:96
#define ERR
Definition: Logger.h:98
#define WAR
Definition: Logger.h:97
double _dnlTotal
Bytes to download or 0 if unknown.
Definition: MediaCurl.cc:78
double uload
Definition: MediaCurl.cc:161
time_t _timeLast
Start last period(~1sec)
Definition: MediaCurl.cc:74
bool reached
Definition: MediaCurl.cc:68
bool fileSizeExceeded
Definition: MediaCurl.cc:69
ByteCount _expectedFileSize
Definition: MediaCurl.cc:71
double _drateTotal
Download rate so far.
Definition: MediaCurl.cc:84
double dload
Definition: MediaCurl.cc:159
#define SET_OPTION_OFFT(opt, val)
Definition: MediaCurl.cc:177
double dload_period
Definition: MediaCurl.cc:151
callback::SendReport< DownloadProgressReport > * report
Definition: MediaCurl.cc:70
long secs
Definition: MediaCurl.cc:153
int _dnlPercent
Percent completed or 0 if _dnlTotal is unknown.
Definition: MediaCurl.cc:82
CURL * curl
Definition: MediaCurl.cc:65
Url url
Definition: MediaCurl.cc:66
double _drateLast
Download rate in last period.
Definition: MediaCurl.cc:85
time_t ltime
Definition: MediaCurl.cc:157
time_t _timeNow
Now.
Definition: MediaCurl.cc:76
#define SET_OPTION(opt, val)
Definition: MediaCurl.cc:170
double drate_period
Definition: MediaCurl.cc:149
double drate_avg
Definition: MediaCurl.cc:155
time_t _timeStart
Start total stats.
Definition: MediaCurl.cc:73
time_t _timeRcv
Start of no-data timeout.
Definition: MediaCurl.cc:75
double _dnlNow
Bytes downloaded now.
Definition: MediaCurl.cc:80
double _dnlLast
Bytes downloaded at period start.
Definition: MediaCurl.cc:79
time_t timeout
Definition: MediaCurl.cc:67
Convenience interface for handling authentication data of media user.
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:93
void resetDispose()
Set no dispose function.
Definition: AutoDispose.h:162
Store and operate with byte count.
Definition: ByteCount.h:31
Base class for Exception.
Definition: Exception.h:146
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition: Exception.cc:91
Url manipulation class.
Definition: Url.h:92
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:528
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:492
std::string getUsername(EEncoding eflag=zypp::url::E_DECODED) const
Returns the username from the URL authority.
Definition: Url.cc:567
std::string getPathName(EEncoding eflag=zypp::url::E_DECODED) const
Returns the path name from the URL.
Definition: Url.cc:599
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:655
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition: Url.cc:759
std::string getHost(EEncoding eflag=zypp::url::E_DECODED) const
Returns the hostname or IP from the URL authority.
Definition: Url.cc:583
bool isValid() const
Verifies the Url.
Definition: Url.cc:484
static ZConfig & instance()
Singleton ctor.
Definition: Resolver.cc:126
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
bool userMayRWX() const
Definition: PathInfo.h:353
const Pathname & path() const
Return current Pathname.
Definition: PathInfo.h:246
Pathname extend(const std::string &r) const
Append string r to the last component of the path.
Definition: Pathname.h:170
Pathname dirname() const
Return all but the last component od this path.
Definition: Pathname.h:124
const std::string & asString() const
String representation.
Definition: Pathname.h:91
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
Pathname absolutename() const
Return this path, adding a leading '/' if relative.
Definition: Pathname.h:139
const char * c_str() const
String representation.
Definition: Pathname.h:110
void save()
Saves any unsaved credentials added via addUserCred() or addGlobalCred() methods.
AuthData_Ptr getCred(const Url &url)
Get credentials for the specified url.
void addCred(const AuthData &cred)
Add new credentials with user callbacks.
Curl HTTP authentication data.
Definition: MediaUserAuth.h:74
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_* ...
Implementation class for FTP, HTTP and HTTPS MediaHandler.
Definition: MediaCurl.h:33
virtual void setupEasy()
initializes the curl easy handle with the data from the url
Definition: MediaCurl.cc:260
Url getFileUrl(const Pathname &filename) const
concatenate the attach url and the filename to a complete download url
Definition: MediaCurl.cc:591
static void setCookieFile(const Pathname &)
Definition: MediaCurl.cc:228
virtual bool getDoesFileExist(const Pathname &filename) const override
Repeatedly calls doGetDoesFileExist() until it successfully returns, fails unexpectedly,...
Definition: MediaCurl.cc:662
@ OPTION_NO_IFMODSINCE
to not add a IFMODSINCE header if target exists
Definition: MediaCurl.h:44
@ OPTION_NO_REPORT_START
do not send a start ProgressReport
Definition: MediaCurl.h:46
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:1343
std::string _currentCookieFile
Definition: MediaCurl.h:170
static int aliveCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
Definition: MediaCurl.cc:1286
static Pathname _cookieFile
Definition: MediaCurl.h:171
static int progressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
Callback reporting download progress.
Definition: MediaCurl.cc:1300
std::string _lastRedirect
to log/report redirections
Definition: MediaCurl.h:173
Url clearQueryString(const Url &url) const
Definition: MediaCurl.cc:217
virtual void attachTo(bool next=false) override
Call concrete handler to attach the media.
Definition: MediaCurl.cc:527
virtual 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.
Definition: MediaCurl.cc:1270
char _curlError[CURL_ERROR_SIZE]
Definition: MediaCurl.h:177
void checkProtocol(const Url &url) const
check the url is supported by the curl library
Definition: MediaCurl.cc:235
virtual void getFileCopy(const Pathname &srcFilename, const Pathname &targetFilename, const ByteCount &expectedFileSize_r) const override
Definition: MediaCurl.cc:616
bool detectDirIndex() 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:693
TransferSettings _settings
Definition: MediaCurl.h:179
virtual void doGetFileCopy(const Pathname &srcFilename, const Pathname &targetFilename, callback::SendReport< DownloadProgressReport > &_report, const ByteCount &expectedFileSize_r, RequestOptions options=OPTION_NONE) const
Definition: MediaCurl.cc:1020
virtual 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:562
virtual void getDir(const Pathname &dirname, bool recurse_r) const override
Call concrete handler to provide directory content (not recursive!) below attach point.
Definition: MediaCurl.cc:1237
TransferSettings & settings()
Definition: MediaCurl.cc:222
bool authenticate(const std::string &availAuthTypes, bool firstTry) const
Definition: MediaCurl.cc:1353
virtual void getFile(const Pathname &filename, const ByteCount &expectedFileSize_r) const override
Call concrete handler to provide file below attach point.
Definition: MediaCurl.cc:607
static CURL * progressCallback_getcurl(void *clientp)
Definition: MediaCurl.cc:1316
virtual void releaseFrom(const std::string &ejectDev) override
Call concrete handler to release the media.
Definition: MediaCurl.cc:586
void doGetFileCopyFile(const Pathname &srcFilename, const Pathname &dest, FILE *file, callback::SendReport< DownloadProgressReport > &_report, const ByteCount &expectedFileSize_r, RequestOptions options=OPTION_NONE) const
Definition: MediaCurl.cc:1130
virtual void disconnectFrom() override
Definition: MediaCurl.cc:569
virtual bool doGetDoesFileExist(const Pathname &filename) const
Definition: MediaCurl.cc:834
curl_slist * _customHeaders
Definition: MediaCurl.h:178
std::string getAuthHint() const
Return a comma separated list of available authentication methods supported by server.
Definition: MediaCurl.cc:1324
Just inherits Exception to separate media exceptions.
Abstract base class for 'physical' MediaHandler like MediaCD, etc.
Definition: MediaHandler.h:45
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.
Definition: MediaHandler.h:507
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.
Definition: MediaHandler.h:110
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.
Media source internally used by MediaManager and MediaHandler.
Definition: MediaSource.h:37
const std::string & hint() const
comma separated list of available authentication types
Holds transfer setting.
std::string proxy() const
proxy host
long maxDownloadSpeed() const
Maximum download speed (bytes per second)
long connectTimeout() const
connection timeout
std::string password() const
auth password
long timeout() const
transfer timeout
Headers::const_iterator headersEnd() const
end iterators to additional headers
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.
void setAuthType(std::string &&val_r)
set the allowed authentication types
void setUsername(std::string &&val_r)
sets the auth username
void setUserAgentString(std::string &&val_r)
sets the user agent ie: "Mozilla v3"
void setConnectTimeout(long t)
set the connect timeout
std::string userAgentString() const
user agent string
void setPassword(std::string &&val_r)
sets the auth password
void addHeader(std::string &&val_r)
add a header, on the form "Foo: Bar"
std::string proxyUserPassword() const
returns the proxy user and password as a user:pass string
bool verifyHostEnabled() const
Whether to verify host for ssl.
Pathname clientCertificatePath() const
SSL client certificate file.
Pathname certificateAuthoritiesPath() const
SSL certificate authorities path ( default: /etc/ssl/certs )
bool headRequestsAllowed() const
whether HEAD requests are allowed
std::string proxyUsername() const
proxy auth username
std::string authType() const
get the allowed authentication types
bool proxyEnabled() const
proxy is enabled
std::string username() const
auth username
Pathname clientKeyPath() const
SSL client key file.
void setTimeout(long t)
set the transfer timeout
Headers::const_iterator headersBegin() const
begin iterators to additional headers
bool verifyPeerEnabled() const
Whether to verify peer for ssl.
int ZYPP_MEDIA_CURL_IPRESOLVE()
Definition: CurlHelper.h:36
void fillSettingsFromUrl(const Url &url, media::TransferSettings &s)
Fills the settings structure using options passed on the url for example ?timeout=x&proxy=foo.
Definition: CurlHelper.cc:102
size_t log_redirects_curl(char *ptr, size_t size, size_t nmemb, void *userdata)
Definition: CurlHelper.cc:62
const char * anonymousIdHeader()
initialized only once, this gets the anonymous id from the target, which we pass in the http header
Definition: CurlHelper.cc:286
void globalInitCurlOnce()
Definition: CurlHelper.cc:19
const char * distributionFlavorHeader()
initialized only once, this gets the distribution flavor from the target, which we pass in the http h...
Definition: CurlHelper.cc:300
std::string curlUnEscape(std::string text_r)
Definition: CurlHelper.cc:343
const char * agentString()
initialized only once, this gets the agent string which also includes the curl version
Definition: CurlHelper.cc:314
void fillSettingsSystemProxy(const Url &url, media::TransferSettings &s)
Reads the system proxy configuration and fills the settings structure proxy information.
Definition: CurlHelper.cc:250
Url clearQueryString(const Url &url)
Definition: CurlHelper.cc:350
int log_curl(CURL *curl, curl_infotype info, char *ptr, size_t len, void *max_lvl)
Definition: CurlHelper.cc:28
mode_t applyUmaskTo(mode_t mode_r)
Modify mode_r according to the current umask ( mode_r & ~getUmask() ).
Definition: PathInfo.h:813
int unlink(const Pathname &path)
Like 'unlink'.
Definition: PathInfo.cc:662
int rename(const Pathname &oldpath, const Pathname &newpath)
Like 'rename'.
Definition: PathInfo.cc:704
int rmdir(const Pathname &path)
Like 'rmdir'.
Definition: PathInfo.cc:367
int assert_dir(const Pathname &path, unsigned mode)
Like 'mkdir -p'.
Definition: PathInfo.cc:320
int assert_file_mode(const Pathname &path, unsigned mode)
Like assert_file but enforce mode even if the file already exists.
Definition: PathInfo.cc:1164
std::list< DirEntry > DirContent
Returned by readdir.
Definition: PathInfo.h:547
shared_ptr< CurlAuthData > CurlAuthData_Ptr
shared_ptr< AuthData > AuthData_Ptr
Definition: MediaUserAuth.h:69
std::string numstring(char n, int w=0)
Definition: String.h:286
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
Definition: String.h:426
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
AutoDispose< const Pathname > ManagedFile
A Pathname plus associated cleanup code to be executed when path is no longer needed.
Definition: ManagedFile.h:27
AutoDispose<int> calling ::close
Definition: AutoDispose.h:281
AutoDispose<FILE*> calling ::fclose
Definition: AutoDispose.h:292
Structure holding values of curlrc options.
Definition: CurlConfig.h:17
std::string proxyuserpwd
Definition: CurlConfig.h:39
static int parseConfig(CurlConfig &config, const std::string &filename="")
Parse a curlrc file and store the result in the config structure.
Definition: CurlConfig.cc:24
Convenient building of std::string with boost::format.
Definition: String.h:250