libzypp  17.28.5
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  // add custom headers for download.opensuse.org (bsc#955801)
166  if ( _url.getHost() == "download.opensuse.org" )
167  {
168  vol_settings.addHeader(anonymousIdHeader());
169  vol_settings.addHeader(distributionFlavorHeader());
170  }
171  vol_settings.addHeader("Pragma:");
172 
173  _settings.setTimeout(ZConfig::instance().download_transfer_timeout());
175 
177 
178  // fill some settings from url query parameters
179  try
180  {
182  }
183  catch ( const MediaException &e )
184  {
185  disconnectFrom();
186  ZYPP_RETHROW(e);
187  }
188  // if the proxy was not set (or explicitly unset) by url, then look...
189  if ( _settings.proxy().empty() )
190  {
191  // ...at the system proxy settings
193  }
194 
196  switch ( env::ZYPP_MEDIA_CURL_IPRESOLVE() )
197  {
198  case 4: SET_OPTION(CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); break;
199  case 6: SET_OPTION(CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); break;
200  }
201 
205  SET_OPTION(CURLOPT_CONNECTTIMEOUT, _settings.connectTimeout());
206  // If a transfer timeout is set, also set CURLOPT_TIMEOUT to an upper limit
207  // just in case curl does not trigger its progress callback frequently
208  // enough.
209  if ( _settings.timeout() )
210  {
211  SET_OPTION(CURLOPT_TIMEOUT, 3600L);
212  }
213 
214  // follow any Location: header that the server sends as part of
215  // an HTTP header (#113275)
216  SET_OPTION(CURLOPT_FOLLOWLOCATION, 1L);
217  // 3 redirects seem to be too few in some cases (bnc #465532)
218  SET_OPTION(CURLOPT_MAXREDIRS, 6L);
219 
220  if ( _url.getScheme() == "https" )
221  {
222 #if CURLVERSION_AT_LEAST(7,19,4)
223  // restrict following of redirections from https to https only
224  if ( _url.getHost() == "download.opensuse.org" )
225  SET_OPTION( CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS );
226  else
227  SET_OPTION( CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS );
228 #endif
229 
232  {
234  }
235 
237  {
238  SET_OPTION(CURLOPT_SSLCERT, _settings.clientCertificatePath().c_str());
239  }
240  if( ! _settings.clientKeyPath().empty() )
241  {
242  SET_OPTION(CURLOPT_SSLKEY, _settings.clientKeyPath().c_str());
243  }
244 
245 #ifdef CURLSSLOPT_ALLOW_BEAST
246  // see bnc#779177
247  ret = curl_easy_setopt( _curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_ALLOW_BEAST );
248  if ( ret != 0 ) {
249  disconnectFrom();
251  }
252 #endif
253  SET_OPTION(CURLOPT_SSL_VERIFYPEER, _settings.verifyPeerEnabled() ? 1L : 0L);
254  SET_OPTION(CURLOPT_SSL_VERIFYHOST, _settings.verifyHostEnabled() ? 2L : 0L);
255  // bnc#903405 - POODLE: libzypp should only talk TLS
256  SET_OPTION(CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
257  }
258 
259  SET_OPTION(CURLOPT_USERAGENT, _settings.userAgentString().c_str() );
260 
261  /* Fixes bsc#1174011 "auth=basic ignored in some cases"
262  * We should proactively add the password to the request if basic auth is configured
263  * and a password is available in the credentials but not in the URL.
264  *
265  * We will be a bit paranoid here and require that the URL has a user embedded, otherwise we go the default route
266  * and ask the server first about the auth method
267  */
268  if ( _settings.authType() == "basic"
269  && _settings.username().size()
270  && !_settings.password().size() ) {
271 
272  CredentialManager cm(CredManagerOptions(ZConfig::instance().repoManagerRoot()));
273  const auto cred = cm.getCred( _url );
274  if ( cred && cred->valid() ) {
275  if ( !_settings.username().size() )
276  _settings.setUsername(cred->username());
277  _settings.setPassword(cred->password());
278  }
279  }
280 
281  /*---------------------------------------------------------------*
282  CURLOPT_USERPWD: [user name]:[password]
283 
284  Url::username/password -> CURLOPT_USERPWD
285  If not provided, anonymous FTP identification
286  *---------------------------------------------------------------*/
287 
288  if ( _settings.userPassword().size() )
289  {
290  SET_OPTION(CURLOPT_USERPWD, _settings.userPassword().c_str());
291  std::string use_auth = _settings.authType();
292  if (use_auth.empty())
293  use_auth = "digest,basic"; // our default
294  long auth = CurlAuthData::auth_type_str2long(use_auth);
295  if( auth != CURLAUTH_NONE)
296  {
297  DBG << "Enabling HTTP authentication methods: " << use_auth
298  << " (CURLOPT_HTTPAUTH=" << auth << ")" << std::endl;
299  SET_OPTION(CURLOPT_HTTPAUTH, auth);
300  }
301  }
302 
303  if ( _settings.proxyEnabled() && ! _settings.proxy().empty() )
304  {
305  DBG << "Proxy: '" << _settings.proxy() << "'" << endl;
306  SET_OPTION(CURLOPT_PROXY, _settings.proxy().c_str());
307  SET_OPTION(CURLOPT_PROXYAUTH, CURLAUTH_BASIC|CURLAUTH_DIGEST|CURLAUTH_NTLM );
308  /*---------------------------------------------------------------*
309  * CURLOPT_PROXYUSERPWD: [user name]:[password]
310  *
311  * Url::option(proxyuser and proxypassword) -> CURLOPT_PROXYUSERPWD
312  * If not provided, $HOME/.curlrc is evaluated
313  *---------------------------------------------------------------*/
314 
315  std::string proxyuserpwd = _settings.proxyUserPassword();
316 
317  if ( proxyuserpwd.empty() )
318  {
319  CurlConfig curlconf;
320  CurlConfig::parseConfig(curlconf); // parse ~/.curlrc
321  if ( curlconf.proxyuserpwd.empty() )
322  DBG << "Proxy: ~/.curlrc does not contain the proxy-user option" << endl;
323  else
324  {
325  proxyuserpwd = curlconf.proxyuserpwd;
326  DBG << "Proxy: using proxy-user from ~/.curlrc" << endl;
327  }
328  }
329  else
330  {
331  DBG << "Proxy: using provided proxy-user '" << _settings.proxyUsername() << "'" << endl;
332  }
333 
334  if ( ! proxyuserpwd.empty() )
335  {
336  SET_OPTION(CURLOPT_PROXYUSERPWD, curlUnEscape( proxyuserpwd ).c_str());
337  }
338  }
339 #if CURLVERSION_AT_LEAST(7,19,4)
340  else if ( _settings.proxy() == EXPLICITLY_NO_PROXY )
341  {
342  // Explicitly disabled in URL (see fillSettingsFromUrl()).
343  // This should also prevent libcurl from looking into the environment.
344  DBG << "Proxy: explicitly NOPROXY" << endl;
345  SET_OPTION(CURLOPT_NOPROXY, "*");
346  }
347 #endif
348  else
349  {
350  DBG << "Proxy: not explicitly set" << endl;
351  DBG << "Proxy: libcurl may look into the environment" << endl;
352  }
353 
355  if ( _settings.minDownloadSpeed() != 0 )
356  {
357  SET_OPTION(CURLOPT_LOW_SPEED_LIMIT, _settings.minDownloadSpeed());
358  // default to 10 seconds at low speed
359  SET_OPTION(CURLOPT_LOW_SPEED_TIME, 60L);
360  }
361 
362 #if CURLVERSION_AT_LEAST(7,15,5)
363  if ( _settings.maxDownloadSpeed() != 0 )
364  SET_OPTION_OFFT(CURLOPT_MAX_RECV_SPEED_LARGE, _settings.maxDownloadSpeed());
365 #endif
366 
367  /*---------------------------------------------------------------*
368  *---------------------------------------------------------------*/
369 
372  if ( str::strToBool( _url.getQueryParam( "cookies" ), true ) )
373  SET_OPTION(CURLOPT_COOKIEFILE, _currentCookieFile.c_str() );
374  else
375  MIL << "No cookies requested" << endl;
376  SET_OPTION(CURLOPT_COOKIEJAR, _currentCookieFile.c_str() );
377  SET_OPTION(CURLOPT_PROGRESSFUNCTION, &progressCallback );
378  SET_OPTION(CURLOPT_NOPROGRESS, 0L);
379 
380 #if CURLVERSION_AT_LEAST(7,18,0)
381  // bnc #306272
382  SET_OPTION(CURLOPT_PROXY_TRANSFER_MODE, 1L );
383 #endif
384  // append settings custom headers to curl
385  for ( const auto &header : vol_settings.headers() )
386  {
387  // MIL << "HEADER " << *it << std::endl;
388 
389  _customHeaders = curl_slist_append(_customHeaders, header.c_str());
390  if ( !_customHeaders )
392  }
393 
394  SET_OPTION(CURLOPT_HTTPHEADER, _customHeaders);
395 }
396 
398 
399 
400 void MediaCurl::attachTo (bool next)
401 {
402  if ( next )
404 
405  if ( !_url.isValid() )
407 
410  {
412  }
413 
414  disconnectFrom(); // clean _curl if needed
415  _curl = curl_easy_init();
416  if ( !_curl ) {
418  }
419  try
420  {
421  setupEasy();
422  }
423  catch (Exception & ex)
424  {
425  disconnectFrom();
426  ZYPP_RETHROW(ex);
427  }
428 
429  // FIXME: need a derived class to propelly compare url's
431  setMediaSource(media);
432 }
433 
434 bool
436 {
437  return MediaHandler::checkAttachPoint( apoint, true, true);
438 }
439 
441 
443 {
444  if ( _customHeaders )
445  {
446  curl_slist_free_all(_customHeaders);
447  _customHeaders = 0L;
448  }
449 
450  if ( _curl )
451  {
452  curl_easy_cleanup( _curl );
453  _curl = NULL;
454  }
455 }
456 
458 
459 void MediaCurl::releaseFrom( const std::string & ejectDev )
460 {
461  disconnect();
462 }
463 
464 Url MediaCurl::getFileUrl( const Pathname & filename_r ) const
465 {
466  // Simply extend the URLs pathname. An 'absolute' URL path
467  // is achieved by encoding the leading '/' in an URL path:
468  // URL: ftp://user@server -> ~user
469  // URL: ftp://user@server/ -> ~user
470  // URL: ftp://user@server// -> ~user
471  // URL: ftp://user@server/%2F -> /
472  // ^- this '/' is just a separator
473  Url newurl( _url );
474  newurl.setPathName( ( Pathname("./"+_url.getPathName()) / filename_r ).asString().substr(1) );
475  return newurl;
476 }
477 
479 
480 void MediaCurl::getFile( const OnMediaLocation &file ) const
481 {
482  // Use absolute file name to prevent access of files outside of the
483  // hierarchy below the attach point.
484  getFileCopy( file, localPath(file.filename()).absolutename() );
485 }
486 
488 
489 void MediaCurl::getFileCopy( const OnMediaLocation & srcFile , const Pathname & target ) const
490 {
491 
492  const auto &filename = srcFile.filename();
493 
495 
496  Url fileurl(getFileUrl(filename));
497 
498  bool retry = false;
499 
500  do
501  {
502  try
503  {
504  doGetFileCopy( srcFile, target, report );
505  retry = false;
506  }
507  // retry with proper authentication data
508  catch (MediaUnauthorizedException & ex_r)
509  {
510  if(authenticate(ex_r.hint(), !retry))
511  retry = true;
512  else
513  {
514  report->finish(fileurl, zypp::media::DownloadProgressReport::ACCESS_DENIED, ex_r.asUserHistory());
515  ZYPP_RETHROW(ex_r);
516  }
517  }
518  // unexpected exception
519  catch (MediaException & excpt_r)
520  {
522  if( typeid(excpt_r) == typeid( media::MediaFileNotFoundException ) ||
523  typeid(excpt_r) == typeid( media::MediaNotAFileException ) )
524  {
526  }
527  report->finish(fileurl, reason, excpt_r.asUserHistory());
528  ZYPP_RETHROW(excpt_r);
529  }
530  }
531  while (retry);
532 
533  report->finish(fileurl, zypp::media::DownloadProgressReport::NO_ERROR, "");
534 }
535 
537 
538 bool MediaCurl::getDoesFileExist( const Pathname & filename ) const
539 {
540  bool retry = false;
541 
542  do
543  {
544  try
545  {
546  return doGetDoesFileExist( filename );
547  }
548  // authentication problem, retry with proper authentication data
549  catch (MediaUnauthorizedException & ex_r)
550  {
551  if(authenticate(ex_r.hint(), !retry))
552  retry = true;
553  else
554  ZYPP_RETHROW(ex_r);
555  }
556  // unexpected exception
557  catch (MediaException & excpt_r)
558  {
559  ZYPP_RETHROW(excpt_r);
560  }
561  }
562  while (retry);
563 
564  return false;
565 }
566 
568 
570  CURLcode code,
571  bool timeout_reached) const
572 {
573  if ( code != 0 )
574  {
575  Url url;
576  if (filename.empty())
577  url = _url;
578  else
579  url = getFileUrl(filename);
580 
581  std::string err;
582  {
583  switch ( code )
584  {
585  case CURLE_UNSUPPORTED_PROTOCOL:
586  err = " Unsupported protocol";
587  if ( !_lastRedirect.empty() )
588  {
589  err += " or redirect (";
590  err += _lastRedirect;
591  err += ")";
592  }
593  break;
594  case CURLE_URL_MALFORMAT:
595  case CURLE_URL_MALFORMAT_USER:
596  err = " Bad URL";
597  break;
598  case CURLE_LOGIN_DENIED:
599  ZYPP_THROW(
600  MediaUnauthorizedException(url, "Login failed.", _curlError, ""));
601  break;
602  case CURLE_HTTP_RETURNED_ERROR:
603  {
604  long httpReturnCode = 0;
605  CURLcode infoRet = curl_easy_getinfo( _curl,
606  CURLINFO_RESPONSE_CODE,
607  &httpReturnCode );
608  if ( infoRet == CURLE_OK )
609  {
610  std::string msg = "HTTP response: " + str::numstring( httpReturnCode );
611  switch ( httpReturnCode )
612  {
613  case 401:
614  {
615  std::string auth_hint = getAuthHint();
616 
617  DBG << msg << " Login failed (URL: " << url.asString() << ")" << std::endl;
618  DBG << "MediaUnauthorizedException auth hint: '" << auth_hint << "'" << std::endl;
619 
621  url, "Login failed.", _curlError, auth_hint
622  ));
623  }
624 
625  case 502: // bad gateway (bnc #1070851)
626  case 503: // service temporarily unavailable (bnc #462545)
628  case 504: // gateway timeout
630  case 403:
631  {
632  std::string msg403;
633  if ( url.getHost().find(".suse.com") != std::string::npos )
634  msg403 = _("Visit the SUSE Customer Center to check whether your registration is valid and has not expired.");
635  else if (url.asString().find("novell.com") != std::string::npos)
636  msg403 = _("Visit the Novell Customer Center to check whether your registration is valid and has not expired.");
638  }
639  case 404:
640  case 410:
642  }
643 
644  DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
646  }
647  else
648  {
649  std::string msg = "Unable to retrieve HTTP response:";
650  DBG << msg << " (URL: " << url.asString() << ")" << std::endl;
652  }
653  }
654  break;
655  case CURLE_FTP_COULDNT_RETR_FILE:
656 #if CURLVERSION_AT_LEAST(7,16,0)
657  case CURLE_REMOTE_FILE_NOT_FOUND:
658 #endif
659  case CURLE_FTP_ACCESS_DENIED:
660  case CURLE_TFTP_NOTFOUND:
661  err = "File not found";
663  break;
664  case CURLE_BAD_PASSWORD_ENTERED:
665  case CURLE_FTP_USER_PASSWORD_INCORRECT:
666  err = "Login failed";
667  break;
668  case CURLE_COULDNT_RESOLVE_PROXY:
669  case CURLE_COULDNT_RESOLVE_HOST:
670  case CURLE_COULDNT_CONNECT:
671  case CURLE_FTP_CANT_GET_HOST:
672  err = "Connection failed";
673  break;
674  case CURLE_WRITE_ERROR:
675  err = "Write error";
676  break;
677  case CURLE_PARTIAL_FILE:
678  case CURLE_OPERATION_TIMEDOUT:
679  timeout_reached = true; // fall though to TimeoutException
680  // fall though...
681  case CURLE_ABORTED_BY_CALLBACK:
682  if( timeout_reached )
683  {
684  err = "Timeout reached";
686  }
687  else
688  {
689  err = "User abort";
690  }
691  break;
692  case CURLE_SSL_PEER_CERTIFICATE:
693  default:
694  err = "Curl error " + str::numstring( code );
695  break;
696  }
697 
698  // uhm, no 0 code but unknown curl exception
700  }
701  }
702  else
703  {
704  // actually the code is 0, nothing happened
705  }
706 }
707 
709 
710 bool MediaCurl::doGetDoesFileExist( const Pathname & filename ) const
711 {
712  DBG << filename.asString() << endl;
713 
714  if(!_url.isValid())
716 
717  if(_url.getHost().empty())
719 
720  Url url(getFileUrl(filename));
721 
722  DBG << "URL: " << url.asString() << endl;
723  // Use URL without options and without username and passwd
724  // (some proxies dislike them in the URL).
725  // Curl seems to need the just scheme, hostname and a path;
726  // the rest was already passed as curl options (in attachTo).
727  Url curlUrl( clearQueryString(url) );
728 
729  //
730  // See also Bug #154197 and ftp url definition in RFC 1738:
731  // The url "ftp://user@host/foo/bar/file" contains a path,
732  // that is relative to the user's home.
733  // The url "ftp://user@host//foo/bar/file" (or also with
734  // encoded slash as %2f) "ftp://user@host/%2ffoo/bar/file"
735  // contains an absolute path.
736  //
737  _lastRedirect.clear();
738  std::string urlBuffer( curlUrl.asString());
739  CURLcode ret = curl_easy_setopt( _curl, CURLOPT_URL,
740  urlBuffer.c_str() );
741  if ( ret != 0 ) {
743  }
744 
745  // instead of returning no data with NOBODY, we return
746  // little data, that works with broken servers, and
747  // works for ftp as well, because retrieving only headers
748  // ftp will return always OK code ?
749  // See http://curl.haxx.se/docs/knownbugs.html #58
750  if ( (_url.getScheme() == "http" || _url.getScheme() == "https") &&
752  ret = curl_easy_setopt( _curl, CURLOPT_NOBODY, 1L );
753  else
754  ret = curl_easy_setopt( _curl, CURLOPT_RANGE, "0-1" );
755 
756  if ( ret != 0 ) {
757  curl_easy_setopt( _curl, CURLOPT_NOBODY, 0L);
758  curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
759  /* yes, this is why we never got to get NOBODY working before,
760  because setting it changes this option too, and we also
761  need to reset it
762  See: http://curl.haxx.se/mail/archive-2005-07/0073.html
763  */
764  curl_easy_setopt( _curl, CURLOPT_HTTPGET, 1L );
766  }
767 
768  AutoFILE file { ::fopen( "/dev/null", "w" ) };
769  if ( !file ) {
770  ERR << "fopen failed for /dev/null" << endl;
771  curl_easy_setopt( _curl, CURLOPT_NOBODY, 0L);
772  curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
773  /* yes, this is why we never got to get NOBODY working before,
774  because setting it changes this option too, and we also
775  need to reset it
776  See: http://curl.haxx.se/mail/archive-2005-07/0073.html
777  */
778  curl_easy_setopt( _curl, CURLOPT_HTTPGET, 1L );
779  if ( ret != 0 ) {
781  }
782  ZYPP_THROW(MediaWriteException("/dev/null"));
783  }
784 
785  ret = curl_easy_setopt( _curl, CURLOPT_WRITEDATA, (*file) );
786  if ( ret != 0 ) {
787  std::string err( _curlError);
788  curl_easy_setopt( _curl, CURLOPT_RANGE, NULL );
789  curl_easy_setopt( _curl, CURLOPT_NOBODY, 0L);
790  /* yes, this is why we never got to get NOBODY working before,
791  because setting it changes this option too, and we also
792  need to reset it
793  See: http://curl.haxx.se/mail/archive-2005-07/0073.html
794  */
795  curl_easy_setopt( _curl, CURLOPT_HTTPGET, 1L );
796  if ( ret != 0 ) {
798  }
800  }
801 
802  CURLcode ok = curl_easy_perform( _curl );
803  MIL << "perform code: " << ok << " [ " << curl_easy_strerror(ok) << " ]" << endl;
804 
805  // reset curl settings
806  if ( _url.getScheme() == "http" || _url.getScheme() == "https" )
807  {
808  curl_easy_setopt( _curl, CURLOPT_NOBODY, 0L);
809  if ( ret != 0 ) {
811  }
812 
813  /* yes, this is why we never got to get NOBODY working before,
814  because setting it changes this option too, and we also
815  need to reset it
816  See: http://curl.haxx.se/mail/archive-2005-07/0073.html
817  */
818  curl_easy_setopt( _curl, CURLOPT_HTTPGET, 1L);
819  if ( ret != 0 ) {
821  }
822 
823  }
824  else
825  {
826  // for FTP we set different options
827  curl_easy_setopt( _curl, CURLOPT_RANGE, NULL);
828  if ( ret != 0 ) {
830  }
831  }
832 
833  // as we are not having user interaction, the user can't cancel
834  // the file existence checking, a callback or timeout return code
835  // will be always a timeout.
836  try {
837  evaluateCurlCode( filename, ok, true /* timeout */);
838  }
839  catch ( const MediaFileNotFoundException &e ) {
840  // if the file did not exist then we can return false
841  return false;
842  }
843  catch ( const MediaException &e ) {
844  // some error, we are not sure about file existence, rethrw
845  ZYPP_RETHROW(e);
846  }
847  // exists
848  return ( ok == CURLE_OK );
849 }
850 
852 
853 
854 #if DETECT_DIR_INDEX
855 bool MediaCurl::detectDirIndex() const
856 {
857  if(_url.getScheme() != "http" && _url.getScheme() != "https")
858  return false;
859  //
860  // try to check the effective url and set the not_a_file flag
861  // if the url path ends with a "/", what usually means, that
862  // we've received a directory index (index.html content).
863  //
864  // Note: This may be dangerous and break file retrieving in
865  // case of some server redirections ... ?
866  //
867  bool not_a_file = false;
868  char *ptr = NULL;
869  CURLcode ret = curl_easy_getinfo( _curl,
870  CURLINFO_EFFECTIVE_URL,
871  &ptr);
872  if ( ret == CURLE_OK && ptr != NULL)
873  {
874  try
875  {
876  Url eurl( ptr);
877  std::string path( eurl.getPathName());
878  if( !path.empty() && path != "/" && *path.rbegin() == '/')
879  {
880  DBG << "Effective url ("
881  << eurl
882  << ") seems to provide the index of a directory"
883  << endl;
884  not_a_file = true;
885  }
886  }
887  catch( ... )
888  {}
889  }
890  return not_a_file;
891 }
892 #endif
893 
895 
896 void MediaCurl::doGetFileCopy( const OnMediaLocation &srcFile , const Pathname & target, callback::SendReport<DownloadProgressReport> & report, RequestOptions options ) const
897 {
898  Pathname dest = target.absolutename();
899  if( assert_dir( dest.dirname() ) )
900  {
901  DBG << "assert_dir " << dest.dirname() << " failed" << endl;
902  ZYPP_THROW( MediaSystemException(getFileUrl(srcFile.filename()), "System error on " + dest.dirname().asString()) );
903  }
904 
905  ManagedFile destNew { target.extend( ".new.zypp.XXXXXX" ) };
906  AutoFILE file;
907  {
908  AutoFREE<char> buf { ::strdup( (*destNew).c_str() ) };
909  if( ! buf )
910  {
911  ERR << "out of memory for temp file name" << endl;
912  ZYPP_THROW(MediaSystemException(getFileUrl(srcFile.filename()), "out of memory for temp file name"));
913  }
914 
915  AutoFD tmp_fd { ::mkostemp( buf, O_CLOEXEC ) };
916  if( tmp_fd == -1 )
917  {
918  ERR << "mkstemp failed for file '" << destNew << "'" << endl;
920  }
921  destNew = ManagedFile( (*buf), filesystem::unlink );
922 
923  file = ::fdopen( tmp_fd, "we" );
924  if ( ! file )
925  {
926  ERR << "fopen failed for file '" << destNew << "'" << endl;
928  }
929  tmp_fd.resetDispose(); // don't close it here! ::fdopen moved ownership to file
930  }
931 
932  DBG << "dest: " << dest << endl;
933  DBG << "temp: " << destNew << endl;
934 
935  // set IFMODSINCE time condition (no download if not modified)
936  if( PathInfo(target).isExist() && !(options & OPTION_NO_IFMODSINCE) )
937  {
938  curl_easy_setopt(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
939  curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, (long)PathInfo(target).mtime());
940  }
941  else
942  {
943  curl_easy_setopt(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
944  curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, 0L);
945  }
946  try
947  {
948  doGetFileCopyFile( srcFile, dest, file, report, options);
949  }
950  catch (Exception &e)
951  {
952  curl_easy_setopt(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
953  curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, 0L);
954  ZYPP_RETHROW(e);
955  }
956 
957  long httpReturnCode = 0;
958  CURLcode infoRet = curl_easy_getinfo(_curl,
959  CURLINFO_RESPONSE_CODE,
960  &httpReturnCode);
961  bool modified = true;
962  if (infoRet == CURLE_OK)
963  {
964  DBG << "HTTP response: " + str::numstring(httpReturnCode);
965  if ( httpReturnCode == 304
966  || ( httpReturnCode == 213 && (_url.getScheme() == "ftp" || _url.getScheme() == "tftp") ) ) // not modified
967  {
968  DBG << " Not modified.";
969  modified = false;
970  }
971  DBG << endl;
972  }
973  else
974  {
975  WAR << "Could not get the reponse code." << endl;
976  }
977 
978  if (modified || infoRet != CURLE_OK)
979  {
980  // apply umask
981  if ( ::fchmod( ::fileno(file), filesystem::applyUmaskTo( 0644 ) ) )
982  {
983  ERR << "Failed to chmod file " << destNew << endl;
984  }
985 
986  file.resetDispose(); // we're going to close it manually here
987  if ( ::fclose( file ) )
988  {
989  ERR << "Fclose failed for file '" << destNew << "'" << endl;
991  }
992 
993  // move the temp file into dest
994  if ( rename( destNew, dest ) != 0 ) {
995  ERR << "Rename failed" << endl;
997  }
998  destNew.resetDispose(); // no more need to unlink it
999  }
1000 
1001  DBG << "done: " << PathInfo(dest) << endl;
1002 }
1003 
1005 
1006 void MediaCurl::doGetFileCopyFile( const OnMediaLocation & srcFile, const Pathname & dest, FILE *file, callback::SendReport<DownloadProgressReport> & report, RequestOptions options ) const
1007 {
1008  DBG << srcFile.filename().asString() << endl;
1009 
1010  if(!_url.isValid())
1012 
1013  if(_url.getHost().empty())
1015 
1016  Url url(getFileUrl(srcFile.filename()));
1017 
1018  DBG << "URL: " << url.asString() << endl;
1019  // Use URL without options and without username and passwd
1020  // (some proxies dislike them in the URL).
1021  // Curl seems to need the just scheme, hostname and a path;
1022  // the rest was already passed as curl options (in attachTo).
1023  Url curlUrl( clearQueryString(url) );
1024 
1025  //
1026  // See also Bug #154197 and ftp url definition in RFC 1738:
1027  // The url "ftp://user@host/foo/bar/file" contains a path,
1028  // that is relative to the user's home.
1029  // The url "ftp://user@host//foo/bar/file" (or also with
1030  // encoded slash as %2f) "ftp://user@host/%2ffoo/bar/file"
1031  // contains an absolute path.
1032  //
1033  _lastRedirect.clear();
1034  std::string urlBuffer( curlUrl.asString());
1035  CURLcode ret = curl_easy_setopt( _curl, CURLOPT_URL,
1036  urlBuffer.c_str() );
1037  if ( ret != 0 ) {
1039  }
1040 
1041  ret = curl_easy_setopt( _curl, CURLOPT_WRITEDATA, file );
1042  if ( ret != 0 ) {
1044  }
1045 
1046  // Set callback and perform.
1047  internal::ProgressData progressData(_curl, _settings.timeout(), url, srcFile.downloadSize(), &report);
1048  if (!(options & OPTION_NO_REPORT_START))
1049  report->start(url, dest);
1050  if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, &progressData ) != 0 ) {
1051  WAR << "Can't set CURLOPT_PROGRESSDATA: " << _curlError << endl;;
1052  }
1053 
1054  ret = curl_easy_perform( _curl );
1055 #if CURLVERSION_AT_LEAST(7,19,4)
1056  // bnc#692260: If the client sends a request with an If-Modified-Since header
1057  // with a future date for the server, the server may respond 200 sending a
1058  // zero size file.
1059  // curl-7.19.4 introduces CURLINFO_CONDITION_UNMET to check this condition.
1060  if ( ftell(file) == 0 && ret == 0 )
1061  {
1062  long httpReturnCode = 33;
1063  if ( curl_easy_getinfo( _curl, CURLINFO_RESPONSE_CODE, &httpReturnCode ) == CURLE_OK && httpReturnCode == 200 )
1064  {
1065  long conditionUnmet = 33;
1066  if ( curl_easy_getinfo( _curl, CURLINFO_CONDITION_UNMET, &conditionUnmet ) == CURLE_OK && conditionUnmet )
1067  {
1068  WAR << "TIMECONDITION unmet - retry without." << endl;
1069  curl_easy_setopt(_curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
1070  curl_easy_setopt(_curl, CURLOPT_TIMEVALUE, 0L);
1071  ret = curl_easy_perform( _curl );
1072  }
1073  }
1074  }
1075 #endif
1076 
1077  if ( curl_easy_setopt( _curl, CURLOPT_PROGRESSDATA, NULL ) != 0 ) {
1078  WAR << "Can't unset CURLOPT_PROGRESSDATA: " << _curlError << endl;;
1079  }
1080 
1081  if ( ret != 0 )
1082  {
1083  ERR << "curl error: " << ret << ": " << _curlError
1084  << ", temp file size " << ftell(file)
1085  << " bytes." << endl;
1086 
1087  // the timeout is determined by the progress data object
1088  // which holds whether the timeout was reached or not,
1089  // otherwise it would be a user cancel
1090  try {
1091 
1092  if ( progressData.fileSizeExceeded )
1093  ZYPP_THROW(MediaFileSizeExceededException(url, progressData._expectedFileSize));
1094 
1095  evaluateCurlCode( srcFile.filename(), ret, progressData.reached );
1096  }
1097  catch ( const MediaException &e ) {
1098  // some error, we are not sure about file existence, rethrw
1099  ZYPP_RETHROW(e);
1100  }
1101  }
1102 
1103 #if DETECT_DIR_INDEX
1104  if (!ret && detectDirIndex())
1105  {
1107  }
1108 #endif // DETECT_DIR_INDEX
1109 }
1110 
1112 
1113 void MediaCurl::getDir( const Pathname & dirname, bool recurse_r ) const
1114 {
1115  filesystem::DirContent content;
1116  getDirInfo( content, dirname, /*dots*/false );
1117 
1118  for ( filesystem::DirContent::const_iterator it = content.begin(); it != content.end(); ++it ) {
1119  Pathname filename = dirname + it->name;
1120  int res = 0;
1121 
1122  switch ( it->type ) {
1123  case filesystem::FT_NOT_AVAIL: // old directory.yast contains no typeinfo at all
1124  case filesystem::FT_FILE:
1125  getFile( OnMediaLocation( filename ) );
1126  break;
1127  case filesystem::FT_DIR: // newer directory.yast contain at least directory info
1128  if ( recurse_r ) {
1129  getDir( filename, recurse_r );
1130  } else {
1131  res = assert_dir( localPath( filename ) );
1132  if ( res ) {
1133  WAR << "Ignore error (" << res << ") on creating local directory '" << localPath( filename ) << "'" << endl;
1134  }
1135  }
1136  break;
1137  default:
1138  // don't provide devices, sockets, etc.
1139  break;
1140  }
1141  }
1142 }
1143 
1145 
1146 void MediaCurl::getDirInfo( std::list<std::string> & retlist,
1147  const Pathname & dirname, bool dots ) const
1148 {
1149  getDirectoryYast( retlist, dirname, dots );
1150 }
1151 
1153 
1155  const Pathname & dirname, bool dots ) const
1156 {
1157  getDirectoryYast( retlist, dirname, dots );
1158 }
1159 
1161 //
1162 int MediaCurl::aliveCallback( void *clientp, double /*dltotal*/, double dlnow, double /*ultotal*/, double /*ulnow*/ )
1163 {
1164  internal::ProgressData *pdata = reinterpret_cast<internal::ProgressData *>( clientp );
1165  if( pdata )
1166  {
1167  // Do not propagate dltotal in alive callbacks. MultiCurl uses this to
1168  // prevent a percentage raise while downloading a metalink file. Download
1169  // activity however is indicated by propagating the download rate (via dlnow).
1170  pdata->updateStats( 0.0, dlnow );
1171  return pdata->reportProgress();
1172  }
1173  return 0;
1174 }
1175 
1176 int MediaCurl::progressCallback( void *clientp, double dltotal, double dlnow, double ultotal, double ulnow )
1177 {
1178  internal::ProgressData *pdata = reinterpret_cast<internal::ProgressData *>( clientp );
1179  if( pdata )
1180  {
1181  // work around curl bug that gives us old data
1182  long httpReturnCode = 0;
1183  if ( curl_easy_getinfo( pdata->curl, CURLINFO_RESPONSE_CODE, &httpReturnCode ) != CURLE_OK || httpReturnCode == 0 )
1184  return aliveCallback( clientp, dltotal, dlnow, ultotal, ulnow );
1185 
1186  pdata->updateStats( dltotal, dlnow );
1187  return pdata->reportProgress();
1188  }
1189  return 0;
1190 }
1191 
1193 {
1194  internal::ProgressData *pdata = reinterpret_cast<internal::ProgressData *>(clientp);
1195  return pdata ? pdata->curl : 0;
1196 }
1197 
1199 
1200 std::string MediaCurl::getAuthHint() const
1201 {
1202  long auth_info = CURLAUTH_NONE;
1203 
1204  CURLcode infoRet =
1205  curl_easy_getinfo(_curl, CURLINFO_HTTPAUTH_AVAIL, &auth_info);
1206 
1207  if(infoRet == CURLE_OK)
1208  {
1209  return CurlAuthData::auth_type_long2str(auth_info);
1210  }
1211 
1212  return "";
1213 }
1214 
1219 void MediaCurl::resetExpectedFileSize(void *clientp, const ByteCount &expectedFileSize)
1220 {
1221  internal::ProgressData *data = reinterpret_cast<internal::ProgressData *>(clientp);
1222  if ( data ) {
1223  data->_expectedFileSize = expectedFileSize;
1224  }
1225 }
1226 
1228 
1229 bool MediaCurl::authenticate(const std::string & availAuthTypes, bool firstTry) const
1230 {
1232  CredentialManager cm(CredManagerOptions(ZConfig::instance().repoManagerRoot()));
1233  CurlAuthData_Ptr credentials;
1234 
1235  // get stored credentials
1236  AuthData_Ptr cmcred = cm.getCred(_url);
1237 
1238  if (cmcred && firstTry)
1239  {
1240  credentials.reset(new CurlAuthData(*cmcred));
1241  DBG << "got stored credentials:" << endl << *credentials << endl;
1242  }
1243  // if not found, ask user
1244  else
1245  {
1246 
1247  CurlAuthData_Ptr curlcred;
1248  curlcred.reset(new CurlAuthData());
1250 
1251  // preset the username if present in current url
1252  if (!_url.getUsername().empty() && firstTry)
1253  curlcred->setUsername(_url.getUsername());
1254  // if CM has found some credentials, preset the username from there
1255  else if (cmcred)
1256  curlcred->setUsername(cmcred->username());
1257 
1258  // indicate we have no good credentials from CM
1259  cmcred.reset();
1260 
1261  std::string prompt_msg = str::Format(_("Authentication required for '%s'")) % _url.asString();
1262 
1263  // set available authentication types from the exception
1264  // might be needed in prompt
1265  curlcred->setAuthType(availAuthTypes);
1266 
1267  // ask user
1268  if (auth_report->prompt(_url, prompt_msg, *curlcred))
1269  {
1270  DBG << "callback answer: retry" << endl
1271  << "CurlAuthData: " << *curlcred << endl;
1272 
1273  if (curlcred->valid())
1274  {
1275  credentials = curlcred;
1276  // if (credentials->username() != _url.getUsername())
1277  // _url.setUsername(credentials->username());
1285  }
1286  }
1287  else
1288  {
1289  DBG << "callback answer: cancel" << endl;
1290  }
1291  }
1292 
1293  // set username and password
1294  if (credentials)
1295  {
1296  // HACK, why is this const?
1297  const_cast<MediaCurl*>(this)->_settings.setUsername(credentials->username());
1298  const_cast<MediaCurl*>(this)->_settings.setPassword(credentials->password());
1299 
1300  // set username and password
1301  CURLcode ret = curl_easy_setopt(_curl, CURLOPT_USERPWD, _settings.userPassword().c_str());
1303 
1304  // set available authentication types from the exception
1305  if (credentials->authType() == CURLAUTH_NONE)
1306  credentials->setAuthType(availAuthTypes);
1307 
1308  // set auth type (seems this must be set _after_ setting the userpwd)
1309  if (credentials->authType() != CURLAUTH_NONE)
1310  {
1311  // FIXME: only overwrite if not empty?
1312  const_cast<MediaCurl*>(this)->_settings.setAuthType(credentials->authTypeAsString());
1313  ret = curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, credentials->authType());
1315  }
1316 
1317  if (!cmcred)
1318  {
1319  credentials->setUrl(_url);
1320  cm.addCred(*credentials);
1321  cm.save();
1322  }
1323 
1324  return true;
1325  }
1326 
1327  return false;
1328 }
1329 
1330 //need a out of line definiton, otherwise vtable is emitted for every translation unit
1332 
1333  } // namespace media
1334 } // namespace zypp
1335 //
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:528
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:435
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:244
#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:1229
Implementation class for FTP, HTTP and HTTPS MediaHandler.
Definition: MediaCurl.h:30
const char * anonymousIdHeader()
initialized only once, this gets the anonymous id from the target, which we pass in the http header ...
Definition: CurlHelper.cc:300
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:1176
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:460
Url clearQueryString(const Url &url)
Definition: CurlHelper.cc:364
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:489
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:1162
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:280
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:1113
virtual void getFile(const OnMediaLocation &file) const override
Call concrete handler to provide file below attach point.
Definition: MediaCurl.cc:480
const char * distributionFlavorHeader()
initialized only once, this gets the distribution flavor from the target, which we pass in the http h...
Definition: CurlHelper.cc:314
#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:464
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:459
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:1219
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:759
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:1142
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:492
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
Url clearQueryString(const Url &url) const
Definition: MediaCurl.cc:102
int unlink(const Pathname &path)
Like &#39;unlink&#39;.
Definition: PathInfo.cc:640
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:682
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:569
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:514
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:484
virtual bool doGetDoesFileExist(const Pathname &filename) const
Definition: MediaCurl.cc:710
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:400
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:538
void resetDispose()
Set no dispose function.
Definition: AutoDispose.h:162
void doGetFileCopyFile(const OnMediaLocation &srcFile, const Pathname &dest, FILE *file, callback::SendReport< DownloadProgressReport > &report, RequestOptions options=OPTION_NONE) const
Definition: MediaCurl.cc:1006
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:599
std::string curlUnEscape(std::string text_r)
Definition: CurlHelper.cc:357
std::string getHost(EEncoding eflag=zypp::url::E_DECODED) const
Returns the hostname or IP from the URL authority.
Definition: Url.cc:583
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:1146
virtual void disconnectFrom() override
Definition: MediaCurl.cc:442
static CURL * progressCallback_getcurl(void *clientp)
Definition: MediaCurl.cc:1192
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:92
void setUserAgentString(std::string &&val_r)
sets the user agent ie: "Mozilla v3"
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:218
AutoDispose<FILE*> calling ::fclose
Definition: AutoDispose.h:291
const char * agentString()
initialized only once, this gets the agent string which also includes the curl version ...
Definition: CurlHelper.cc:328
void updateStats(double dltotal=0.0, double dlnow=0.0)
Definition: CurlHelper.cc:411
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:780
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:1200
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:896
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:351
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:567