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