libzypp  17.25.6
CurlHelper.cc
Go to the documentation of this file.
1 #include "CurlHelper.h"
2 
3 #include <zypp/PathInfo.h>
4 #include <zypp/Pathname.h>
5 #include <zypp/Target.h>
6 #include <zypp/base/Logger.h>
7 #include <zypp/base/String.h>
8 #include <zypp/media/ProxyInfo.h>
11 #include <list>
12 
13 using std::endl;
14 using namespace zypp;
15 
16 namespace internal
17 {
18 
20 {
21  // function-level static <=> std::call_once
22  static bool once __attribute__ ((__unused__)) = ( [] {
23  if ( curl_global_init( CURL_GLOBAL_ALL ) != 0 )
24  WAR << "curl global init failed" << std::endl;
25  } (), true );
26 }
27 
28 int log_curl(CURL *curl, curl_infotype info,
29  char *ptr, size_t len, void *max_lvl)
30 {
31  if ( max_lvl == nullptr )
32  return 0;
33 
34  long maxlvl = *((long *)max_lvl);
35 
36  char pfx = ' ';
37  switch( info )
38  {
39  case CURLINFO_TEXT: if ( maxlvl < 1 ) return 0; pfx = '*'; break;
40  case CURLINFO_HEADER_IN: if ( maxlvl < 2 ) return 0; pfx = '<'; break;
41  case CURLINFO_HEADER_OUT: if ( maxlvl < 2 ) return 0; pfx = '>'; break;
42  default:
43  return 0;
44  }
45 
46  std::vector<std::string> lines;
47  str::split( std::string(ptr,len), std::back_inserter(lines), "\r\n" );
48  for( const auto & line : lines )
49  {
50  if ( str::startsWith( line, "Authorization:" ) ) {
51  std::string::size_type pos { line.find( " ", 15 ) }; // Authorization: <type> <credentials>
52  if ( pos == std::string::npos )
53  pos = 15;
54  DBG << pfx << " " << line.substr( 0, pos ) << " <credentials removed>" << std::endl;
55  }
56  else
57  DBG << pfx << " " << line << std::endl;
58  }
59  return 0;
60 }
61 
62 size_t log_redirects_curl( char *ptr, size_t size, size_t nmemb, void *userdata)
63 {
64  // INT << "got header: " << string(ptr, ptr + size*nmemb) << endl;
65 
66  char * lstart = ptr, * lend = ptr;
67  size_t pos = 0;
68  size_t max = size * nmemb;
69  while (pos + 1 < max)
70  {
71  // get line
72  for (lstart = lend; *lend != '\n' && pos < max; ++lend, ++pos);
73 
74  // look for "Location"
75  if ( lstart[0] == 'L'
76  && lstart[1] == 'o'
77  && lstart[2] == 'c'
78  && lstart[3] == 'a'
79  && lstart[4] == 't'
80  && lstart[5] == 'i'
81  && lstart[6] == 'o'
82  && lstart[7] == 'n'
83  && lstart[8] == ':' )
84  {
85  std::string line { lstart, *(lend-1)=='\r' ? lend-1 : lend };
86  DBG << "redirecting to " << line << std::endl;
87  if ( userdata ) {
88  *reinterpret_cast<std::string *>( userdata ) = line;
89  }
90  return max;
91  }
92 
93  // continue with the next line
94  if (pos + 1 < max)
95  {
96  ++lend;
97  ++pos;
98  }
99  else
100  break;
101  }
102 
103  return max;
104 }
105 
111 {
112  {
113  const std::string & param { url.getQueryParam("timeout") };
114  if( ! param.empty() )
115  {
116  long num = str::strtonum<long>(param);
117  if( num >= 0 && num <= TRANSFER_TIMEOUT_MAX )
118  s.setTimeout( num );
119  }
120  }
121  {
122  std::string param { url.getUsername() };
123  if ( ! param.empty() )
124  {
125  s.setUsername( std::move(param) );
126  param = url.getPassword();
127  if ( ! param.empty() )
128  s.setPassword( std::move(param) );
129  }
130  else
131  {
132  // if there is no username, set anonymous auth
133  if ( ( url.getScheme() == "ftp" || url.getScheme() == "tftp" ) && s.username().empty() )
134  s.setAnonymousAuth();
135  }
136  }
137  if ( url.getScheme() == "https" )
138  {
139  s.setVerifyPeerEnabled( false );
140  s.setVerifyHostEnabled( false );
141 
142  const std::string & verify { url.getQueryParam("ssl_verify") };
143  if( verify.empty() || verify == "yes" )
144  {
145  s.setVerifyPeerEnabled( true );
146  s.setVerifyHostEnabled( true );
147  }
148  else if ( verify == "no" )
149  {
150  s.setVerifyPeerEnabled( false );
151  s.setVerifyHostEnabled( false );
152  }
153  else
154  {
155  std::vector<std::string> flags;
156  str::split( verify, std::back_inserter(flags), "," );
157  for ( const auto & flag : flags )
158  {
159  if ( flag == "host" )
160  s.setVerifyHostEnabled( true );
161  else if ( flag == "peer" )
162  s.setVerifyPeerEnabled( true );
163  else
164  ZYPP_THROW( media::MediaBadUrlException(url, "Unknown ssl_verify flag "+flag) );
165  }
166  }
167  }
168  {
169  Pathname ca_path { url.getQueryParam("ssl_capath") };
170  if( ! ca_path.empty() )
171  {
172  if( ! PathInfo(ca_path).isDir() || ! ca_path.absolute() )
173  ZYPP_THROW(media::MediaBadUrlException(url, "Invalid ssl_capath path"));
174  else
175  s.setCertificateAuthoritiesPath( std::move(ca_path) );
176  }
177  }
178  {
179  Pathname client_cert { url.getQueryParam("ssl_clientcert") };
180  if( ! client_cert.empty() )
181  {
182  if( ! PathInfo(client_cert).isFile() || ! client_cert.absolute() )
183  ZYPP_THROW(media::MediaBadUrlException(url, "Invalid ssl_clientcert file"));
184  else
185  s.setClientCertificatePath( std::move(client_cert) );
186  }
187  }
188  {
189  Pathname client_key { url.getQueryParam("ssl_clientkey") };
190  if( ! client_key.empty() )
191  {
192  if( ! PathInfo(client_key).isFile() || ! client_key.absolute() )
193  ZYPP_THROW(media::MediaBadUrlException(url, "Invalid ssl_clientkey file"));
194  else
195  s.setClientKeyPath( std::move(client_key) );
196  }
197  }
198  {
199  std::string param { url.getQueryParam( "proxy" ) };
200  if ( ! param.empty() )
201  {
202  if ( param == EXPLICITLY_NO_PROXY ) {
203  // Workaround TransferSettings shortcoming: With an
204  // empty proxy string, code will continue to look for
205  // valid proxy settings. So set proxy to some non-empty
206  // string, to indicate it has been explicitly disabled.
208  s.setProxyEnabled(false);
209  }
210  else {
211  const std::string & proxyport { url.getQueryParam( "proxyport" ) };
212  if ( ! proxyport.empty() ) {
213  param += ":";
214  param += proxyport;
215  }
216  s.setProxy( std::move(param) );
217  s.setProxyEnabled( true );
218  }
219  }
220  }
221  {
222  std::string param { url.getQueryParam( "proxyuser" ) };
223  if ( ! param.empty() )
224  {
225  s.setProxyUsername( std::move(param) );
226  s.setProxyPassword( url.getQueryParam( "proxypass" ) );
227  }
228  }
229  {
230  // HTTP authentication type
231  std::string param { url.getQueryParam("auth") };
232  if ( ! param.empty() && (url.getScheme() == "http" || url.getScheme() == "https") )
233  {
234  try
235  {
236  media::CurlAuthData::auth_type_str2long (param ); // check if we know it
237  }
238  catch ( const media::MediaException & ex_r )
239  {
240  DBG << "Rethrowing as MediaUnauthorizedException.";
242  }
243  s.setAuthType( std::move(param) );
244  }
245  }
246  {
247  // workarounds
248  const std::string & param { url.getQueryParam("head_requests") };
249  if( ! param.empty() && param == "no" )
250  s.setHeadRequestsAllowed( false );
251  }
252 }
253 
259 {
260  media::ProxyInfo proxy_info;
261  if ( proxy_info.useProxyFor( url ) )
262  {
263  // We must extract any 'user:pass' from the proxy url
264  // otherwise they won't make it into curl (.curlrc wins).
265  try {
266  Url u( proxy_info.proxy( url ) );
268  // don't overwrite explicit auth settings
269  if ( s.proxyUsername().empty() )
270  {
273  }
274  s.setProxyEnabled( true );
275  }
276  catch (...) {} // no proxy if URL is malformed
277  }
278 }
279 
280 
282 {
283  int ret = 0;
284  if ( const char * envp = getenv( "ZYPP_MEDIA_CURL_IPRESOLVE" ) )
285  {
286  WAR << "env set: $ZYPP_MEDIA_CURL_IPRESOLVE='" << envp << "'" << std::endl;
287  if ( strcmp( envp, "4" ) == 0 ) ret = 4;
288  else if ( strcmp( envp, "6" ) == 0 ) ret = 6;
289  }
290  return ret;
291 }
292 
293 
294 const char * anonymousIdHeader()
295 {
296  // we need to add the release and identifier to the
297  // agent string.
298  // The target could be not initialized, and then this information
299  // is guessed.
300  static const std::string _value(
302  "X-ZYpp-AnonymousId: %s",
303  Target::anonymousUniqueId( Pathname()/*guess root*/ ).c_str() ) )
304  );
305  return _value.c_str();
306 }
307 
309 {
310  // we need to add the release and identifier to the
311  // agent string.
312  // The target could be not initialized, and then this information
313  // is guessed.
314  static const std::string _value(
316  "X-ZYpp-DistributionFlavor: %s",
317  Target::distributionFlavor( Pathname()/*guess root*/ ).c_str() ) )
318  );
319  return _value.c_str();
320 }
321 
322 const char * agentString()
323 {
324  // we need to add the release and identifier to the
325  // agent string.
326  // The target could be not initialized, and then this information
327  // is guessed.
328  static const std::string _value(
329  str::form(
330  "ZYpp " LIBZYPP_VERSION_STRING " (curl %s) %s"
331  , curl_version_info(CURLVERSION_NOW)->version
332  , Target::targetDistribution( Pathname()/*guess root*/ ).c_str()
333  )
334  );
335  return _value.c_str();
336 }
337 
338 void curlEscape( std::string & str_r,
339  const char char_r, const std::string & escaped_r ) {
340  for ( std::string::size_type pos = str_r.find( char_r );
341  pos != std::string::npos; pos = str_r.find( char_r, pos ) ) {
342  str_r.replace( pos, 1, escaped_r );
343  }
344 }
345 
346 std::string curlEscapedPath( std::string path_r ) {
347  curlEscape( path_r, ' ', "%20" );
348  return path_r;
349 }
350 
351 std::string curlUnEscape( std::string text_r ) {
352  char * tmp = curl_unescape( text_r.c_str(), 0 );
353  std::string ret( tmp );
354  curl_free( tmp );
355  return ret;
356 }
357 
359 {
360  Url curlUrl (url);
361  curlUrl.setUsername( "" );
362  curlUrl.setPassword( "" );
363  curlUrl.setPathParams( "" );
364  curlUrl.setFragment( "" );
365  curlUrl.delQueryParam("cookies");
366  curlUrl.delQueryParam("proxy");
367  curlUrl.delQueryParam("proxyport");
368  curlUrl.delQueryParam("proxyuser");
369  curlUrl.delQueryParam("proxypass");
370  curlUrl.delQueryParam("ssl_capath");
371  curlUrl.delQueryParam("ssl_verify");
372  curlUrl.delQueryParam("ssl_clientcert");
373  curlUrl.delQueryParam("timeout");
374  curlUrl.delQueryParam("auth");
375  curlUrl.delQueryParam("username");
376  curlUrl.delQueryParam("password");
377  curlUrl.delQueryParam("mediahandler");
378  curlUrl.delQueryParam("credentials");
379  curlUrl.delQueryParam("head_requests");
380  return curlUrl;
381 }
382 
383 // bsc#933839: propagate proxy settings passed in the repo URL
384 zypp::Url propagateQueryParams( zypp::Url url_r, const zypp::Url & template_r )
385 {
386  for ( std::string param : { "proxy", "proxyport", "proxyuser", "proxypass"} )
387  {
388  const std::string & value( template_r.getQueryParam( param ) );
389  if ( ! value.empty() )
390  url_r.setQueryParam( param, value );
391  }
392  return url_r;
393 }
394 
395 }
internal::curlUnEscape
std::string curlUnEscape(std::string text_r)
Definition: CurlHelper.cc:351
zypp::Target::distributionFlavor
std::string distributionFlavor() const
This is flavor attribute of the installed base product but does not require the target to be loaded a...
Definition: Target.cc:127
zypp::str::startsWith
bool startsWith(const C_Str &str_r, const C_Str &prefix_r)
alias for hasPrefix
Definition: String.h:1081
zypp::Url::getScheme
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:528
PathInfo.h
zypp::media::MediaException
Just inherits Exception to separate media exceptions.
Definition: MediaException.h:36
internal::agentString
const char * agentString()
initialized only once, this gets the agent string which also includes the curl version
Definition: CurlHelper.cc:322
zypp::media::ProxyInfo
Definition: ProxyInfo.h:30
zypp::Target::targetDistribution
std::string targetDistribution() const
This is register.target attribute of the installed base product.
Definition: Target.cc:102
zypp::Url::setQueryParam
void setQueryParam(const std::string &param, const std::string &value)
Set or add value for the specified query parameter.
Definition: Url.cc:833
zypp::media::TransferSettings::setTimeout
void setTimeout(long t)
set the transfer timeout
Definition: TransferSettings.cc:173
zypp::media::TransferSettings::username
std::string username() const
auth username
Definition: TransferSettings.cc:112
internal::log_curl
int log_curl(CURL *curl, curl_infotype info, char *ptr, size_t len, void *max_lvl)
Definition: CurlHelper.cc:28
zypp::media::MediaBadUrlException
Definition: MediaException.h:270
curl
CURL * curl
Definition: MediaCurl.cc:65
internal::fillSettingsSystemProxy
void fillSettingsSystemProxy(const Url &url, media::TransferSettings &s)
Reads the system proxy configuration and fills the settings structure proxy information.
Definition: CurlHelper.cc:258
ZYPP_THROW
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:392
zypp::Url::setPathParams
void setPathParams(const std::string &params)
Set the path parameters.
Definition: Url.cc:786
ProxyInfo.h
zypp::Url::setUsername
void setUsername(const std::string &user, EEncoding eflag=zypp::url::E_DECODED)
Set the username in the URL authority.
Definition: Url.cc:725
Pathname.h
internal::anonymousIdHeader
const char * anonymousIdHeader()
initialized only once, this gets the anonymous id from the target, which we pass in the http header
Definition: CurlHelper.cc:294
Target.h
zypp::media::TransferSettings::setVerifyHostEnabled
void setVerifyHostEnabled(bool enabled)
Sets whether to verify host for ssl.
Definition: TransferSettings.cc:215
zypp::media::TransferSettings
Holds transfer setting.
Definition: TransferSettings.h:21
zypp::media::TransferSettings::setProxyEnabled
void setProxyEnabled(bool enabled)
whether the proxy is used or not
Definition: TransferSettings.cc:137
internal::fillSettingsFromUrl
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:110
zypp::media::TransferSettings::setUsername
void setUsername(std::string &&val_r)
sets the auth username
Definition: TransferSettings.cc:109
internal::globalInitCurlOnce
void globalInitCurlOnce()
Definition: CurlHelper.cc:19
zypp::Url::setFragment
void setFragment(const std::string &fragment, EEncoding eflag=zypp::url::E_DECODED)
Set the fragment string in the URL.
Definition: Url.cc:717
zypp::Url::getQueryParam
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
zypp::media::ProxyInfo::proxy
std::string proxy(const Url &url) const
Definition: ProxyInfo.cc:43
zypp::media::TransferSettings::setClientCertificatePath
void setClientCertificatePath(Pathname &&val_r)
Sets the SSL client certificate file.
Definition: TransferSettings.cc:229
zypp::media::TransferSettings::setHeadRequestsAllowed
void setHeadRequestsAllowed(bool allowed)
set whether HEAD requests are allowed
Definition: TransferSettings.cc:257
zypp::str::split
unsigned split(const C_Str &line_r, TOutputIterator result_r, const C_Str &sepchars_r=" \t", const Trim trim_r=NO_TRIM)
Split line_r into words.
Definition: String.h:527
zypp::filesystem::PathInfo
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
internal::curlEscapedPath
std::string curlEscapedPath(std::string path_r)
Definition: CurlHelper.cc:346
internal::clearQueryString
Url clearQueryString(const Url &url)
Definition: CurlHelper.cc:358
zypp::Url::asString
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:492
zypp::media::TransferSettings::proxyUsername
std::string proxyUsername() const
proxy auth username
Definition: TransferSettings.cc:154
Logger.h
zypp::media::TransferSettings::setProxy
void setProxy(std::string &&val_r)
proxy to use if it is enabled
Definition: TransferSettings.cc:144
WAR
#define WAR
Definition: Logger.h:80
zypp::media::MediaUnauthorizedException
Definition: MediaException.h:428
zypp::str::form
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:36
internal::curlEscape
void curlEscape(std::string &str_r, const char char_r, const std::string &escaped_r)
Definition: CurlHelper.cc:338
internal::env::getZYPP_MEDIA_CURL_IPRESOLVE
int getZYPP_MEDIA_CURL_IPRESOLVE()
Definition: CurlHelper.cc:281
MediaException.h
zypp
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
zypp::media::TransferSettings::setVerifyPeerEnabled
void setVerifyPeerEnabled(bool enabled)
Sets whether to verify host for ssl.
Definition: TransferSettings.cc:222
_value
Edition * _value
Definition: SysContent.cc:311
internal::propagateQueryParams
zypp::Url propagateQueryParams(zypp::Url url_r, const zypp::Url &template_r)
Definition: CurlHelper.cc:384
zypp::url::E_ENCODED
@ E_ENCODED
Flag to request encoded string(s).
Definition: UrlUtils.h:53
zypp::media::TransferSettings::setProxyPassword
void setProxyPassword(std::string &&val_r)
sets the proxy password
Definition: TransferSettings.cc:157
zypp::Target::anonymousUniqueId
std::string anonymousUniqueId() const
anonymous unique id
Definition: Target.cc:132
internal::distributionFlavorHeader
const char * distributionFlavorHeader()
initialized only once, this gets the distribution flavor from the target, which we pass in the http h...
Definition: CurlHelper.cc:308
zypp::media::ProxyInfo::useProxyFor
bool useProxyFor(const Url &url_r) const
Return true if enabled and url_r does not match noProxy.
Definition: ProxyInfo.cc:55
String.h
zypp::media::TransferSettings::setAuthType
void setAuthType(std::string &&val_r)
set the allowed authentication types
Definition: TransferSettings.cc:250
zypp::filesystem::Pathname
Pathname.
Definition: Pathname.h:45
zypp::sat::detail::size_type
SolvableIdType size_type
Definition: PoolMember.h:126
zypp::media::TransferSettings::setClientKeyPath
void setClientKeyPath(Pathname &&val_r)
Sets the SSL client key file.
Definition: TransferSettings.cc:236
DBG
#define DBG
Definition: Logger.h:78
zypp::media::TransferSettings::setPassword
void setPassword(std::string &&val_r)
sets the auth password
Definition: TransferSettings.cc:115
zypp::media::CurlAuthData::auth_type_str2long
static long auth_type_str2long(std::string &auth_type_str)
Converts a string of comma separated list of authetication type names into a long of ORed CURLAUTH_* ...
Definition: MediaUserAuth.cc:93
zypp::media::TransferSettings::setProxyUsername
void setProxyUsername(std::string &&val_r)
sets the proxy user
Definition: TransferSettings.cc:151
zypp::media::TransferSettings::setCertificateAuthoritiesPath
void setCertificateAuthoritiesPath(Pathname &&val_r)
Sets the SSL certificate authorities path.
Definition: TransferSettings.cc:243
internal
Definition: CurlHelper.cc:17
zypp::IdStringType::c_str
const char * c_str() const
Definition: IdStringType.h:105
zypp::Url::getPassword
std::string getPassword(EEncoding eflag=zypp::url::E_DECODED) const
Returns the password from the URL authority.
Definition: Url.cc:575
CurlHelper.h
MediaUserAuth.h
Convenience interface for handling authentication data of media user.
zypp::media::TransferSettings::setAnonymousAuth
void setAnonymousAuth()
sets anonymous authentication (ie: for ftp)
Definition: TransferSettings.cc:130
url
Url url
Definition: MediaCurl.cc:66
zypp::Url
Url manipulation class.
Definition: Url.h:92
zypp::url::ViewOption::WITH_SCHEME
static const ViewOption WITH_SCHEME
Option to include scheme name in the URL string.
Definition: UrlBase.h:51
internal::log_redirects_curl
size_t log_redirects_curl(char *ptr, size_t size, size_t nmemb, void *userdata)
Definition: CurlHelper.cc:62
zypp::str::trim
std::string trim(const std::string &s, const Trim trim_r)
Definition: String.cc:223
zypp::url::ViewOption::WITH_HOST
static const ViewOption WITH_HOST
Option to include hostname in the URL string.
Definition: UrlBase.h:74
TRANSFER_TIMEOUT_MAX
#define TRANSFER_TIMEOUT_MAX
Definition: CurlHelper.h:22
zypp::Url::setPassword
void setPassword(const std::string &pass, EEncoding eflag=zypp::url::E_DECODED)
Set the password in the URL authority.
Definition: Url.cc:734
zypp::Url::getUsername
std::string getUsername(EEncoding eflag=zypp::url::E_DECODED) const
Returns the username from the URL authority.
Definition: Url.cc:567
EXPLICITLY_NO_PROXY
#define EXPLICITLY_NO_PROXY
Definition: CurlHelper.h:25
zypp::Url::delQueryParam
void delQueryParam(const std::string &param)
remove the specified query parameter.
Definition: Url.cc:840
zypp::Exception::msg
const std::string & msg() const
Return the message string provided to the ctor.
Definition: Exception.h:195
zypp::url::ViewOption::WITH_PORT
static const ViewOption WITH_PORT
Option to include port number in the URL string.
Definition: UrlBase.h:81