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