libzypp  17.22.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 namespace zypp;
14 
15 namespace internal
16 {
17 
19 {
20  // function-level static <=> std::call_once
21  static bool once __attribute__ ((__unused__)) = ( [] {
22  if ( curl_global_init( CURL_GLOBAL_ALL ) != 0 )
23  WAR << "curl global init failed" << std::endl;
24  } (), true );
25 }
26 
27 int log_curl(CURL *curl, curl_infotype info,
28  char *ptr, size_t len, void *max_lvl)
29 {
30  std::string pfx(" ");
31  long lvl = 0;
32  switch( info)
33  {
34  case CURLINFO_TEXT: lvl = 1; pfx = "*"; break;
35  case CURLINFO_HEADER_IN: lvl = 2; pfx = "<"; break;
36  case CURLINFO_HEADER_OUT: lvl = 2; pfx = ">"; break;
37  default: break;
38  }
39  if( lvl > 0 && max_lvl != NULL && lvl <= *((long *)max_lvl))
40  {
41  std::string msg(ptr, len);
42  std::list<std::string> lines;
43  std::list<std::string>::const_iterator line;
44  zypp::str::split(msg, std::back_inserter(lines), "\r\n");
45  for(line = lines.begin(); line != lines.end(); ++line)
46  {
47  DBG << pfx << " " << *line << std::endl;
48  }
49  }
50  return 0;
51 }
52 
53 size_t log_redirects_curl( char *ptr, size_t size, size_t nmemb, void *userdata)
54 {
55  // INT << "got header: " << string(ptr, ptr + size*nmemb) << endl;
56 
57  char * lstart = ptr, * lend = ptr;
58  size_t pos = 0;
59  size_t max = size * nmemb;
60  while (pos + 1 < max)
61  {
62  // get line
63  for (lstart = lend; *lend != '\n' && pos < max; ++lend, ++pos);
64 
65  // look for "Location"
66  if ( lstart[0] == 'L'
67  && lstart[1] == 'o'
68  && lstart[2] == 'c'
69  && lstart[3] == 'a'
70  && lstart[4] == 't'
71  && lstart[5] == 'i'
72  && lstart[6] == 'o'
73  && lstart[7] == 'n'
74  && lstart[8] == ':' )
75  {
76  std::string line { lstart, *(lend-1)=='\r' ? lend-1 : lend };
77  DBG << "redirecting to " << line << std::endl;
78  if ( userdata ) {
79  *reinterpret_cast<std::string *>( userdata ) = line;
80  }
81  return max;
82  }
83 
84  // continue with the next line
85  if (pos + 1 < max)
86  {
87  ++lend;
88  ++pos;
89  }
90  else
91  break;
92  }
93 
94  return max;
95 }
96 
102 {
103  {
104  const std::string & param { url.getQueryParam("timeout") };
105  if( ! param.empty() )
106  {
107  long num = str::strtonum<long>(param);
108  if( num >= 0 && num <= TRANSFER_TIMEOUT_MAX )
109  s.setTimeout( num );
110  }
111  }
112  {
113  std::string param { url.getUsername() };
114  if ( ! param.empty() )
115  {
116  s.setUsername( std::move(param) );
117  param = url.getPassword();
118  if ( ! param.empty() )
119  s.setPassword( std::move(param) );
120  }
121  else
122  {
123  // if there is no username, set anonymous auth
124  if ( ( url.getScheme() == "ftp" || url.getScheme() == "tftp" ) && s.username().empty() )
125  s.setAnonymousAuth();
126  }
127  }
128  if ( url.getScheme() == "https" )
129  {
130  s.setVerifyPeerEnabled( false );
131  s.setVerifyHostEnabled( false );
132 
133  const std::string & verify { url.getQueryParam("ssl_verify") };
134  if( verify.empty() || verify == "yes" )
135  {
136  s.setVerifyPeerEnabled( true );
137  s.setVerifyHostEnabled( true );
138  }
139  else if ( verify == "no" )
140  {
141  s.setVerifyPeerEnabled( false );
142  s.setVerifyHostEnabled( false );
143  }
144  else
145  {
146  std::vector<std::string> flags;
147  str::split( verify, std::back_inserter(flags), "," );
148  for ( const auto & flag : flags )
149  {
150  if ( flag == "host" )
151  s.setVerifyHostEnabled( true );
152  else if ( flag == "peer" )
153  s.setVerifyPeerEnabled( true );
154  else
155  ZYPP_THROW( media::MediaBadUrlException(url, "Unknown ssl_verify flag "+flag) );
156  }
157  }
158  }
159  {
160  Pathname ca_path { url.getQueryParam("ssl_capath") };
161  if( ! ca_path.empty() )
162  {
163  if( ! PathInfo(ca_path).isDir() || ! ca_path.absolute() )
164  ZYPP_THROW(media::MediaBadUrlException(url, "Invalid ssl_capath path"));
165  else
166  s.setCertificateAuthoritiesPath( std::move(ca_path) );
167  }
168  }
169  {
170  Pathname client_cert { url.getQueryParam("ssl_clientcert") };
171  if( ! client_cert.empty() )
172  {
173  if( ! PathInfo(client_cert).isFile() || ! client_cert.absolute() )
174  ZYPP_THROW(media::MediaBadUrlException(url, "Invalid ssl_clientcert file"));
175  else
176  s.setClientCertificatePath( std::move(client_cert) );
177  }
178  }
179  {
180  Pathname client_key { url.getQueryParam("ssl_clientkey") };
181  if( ! client_key.empty() )
182  {
183  if( ! PathInfo(client_key).isFile() || ! client_key.absolute() )
184  ZYPP_THROW(media::MediaBadUrlException(url, "Invalid ssl_clientkey file"));
185  else
186  s.setClientKeyPath( std::move(client_key) );
187  }
188  }
189  {
190  std::string param { url.getQueryParam( "proxy" ) };
191  if ( ! param.empty() )
192  {
193  if ( param == EXPLICITLY_NO_PROXY ) {
194  // Workaround TransferSettings shortcoming: With an
195  // empty proxy string, code will continue to look for
196  // valid proxy settings. So set proxy to some non-empty
197  // string, to indicate it has been explicitly disabled.
199  s.setProxyEnabled(false);
200  }
201  else {
202  const std::string & proxyport { url.getQueryParam( "proxyport" ) };
203  if ( ! proxyport.empty() ) {
204  param += ":";
205  param += proxyport;
206  }
207  s.setProxy( std::move(param) );
208  s.setProxyEnabled( true );
209  }
210  }
211  }
212  {
213  std::string param { url.getQueryParam( "proxyuser" ) };
214  if ( ! param.empty() )
215  {
216  s.setProxyUsername( std::move(param) );
217  s.setProxyPassword( url.getQueryParam( "proxypass" ) );
218  }
219  }
220  {
221  // HTTP authentication type
222  std::string param { url.getQueryParam("auth") };
223  if ( ! param.empty() && (url.getScheme() == "http" || url.getScheme() == "https") )
224  {
225  try
226  {
227  media::CurlAuthData::auth_type_str2long (param ); // check if we know it
228  }
229  catch ( const media::MediaException & ex_r )
230  {
231  DBG << "Rethrowing as MediaUnauthorizedException.";
233  }
234  s.setAuthType( std::move(param) );
235  }
236  }
237  {
238  // workarounds
239  const std::string & param { url.getQueryParam("head_requests") };
240  if( ! param.empty() && param == "no" )
241  s.setHeadRequestsAllowed( false );
242  }
243 }
244 
250 {
251  media::ProxyInfo proxy_info;
252  if ( proxy_info.useProxyFor( url ) )
253  {
254  // We must extract any 'user:pass' from the proxy url
255  // otherwise they won't make it into curl (.curlrc wins).
256  try {
257  Url u( proxy_info.proxy( url ) );
259  // don't overwrite explicit auth settings
260  if ( s.proxyUsername().empty() )
261  {
262  s.setProxyUsername( u.getUsername( url::E_ENCODED ) );
263  s.setProxyPassword( u.getPassword( url::E_ENCODED ) );
264  }
265  s.setProxyEnabled( true );
266  }
267  catch (...) {} // no proxy if URL is malformed
268  }
269 }
270 
271 
273 {
274  int ret = 0;
275  if ( const char * envp = getenv( "ZYPP_MEDIA_CURL_IPRESOLVE" ) )
276  {
277  WAR << "env set: $ZYPP_MEDIA_CURL_IPRESOLVE='" << envp << "'" << std::endl;
278  if ( strcmp( envp, "4" ) == 0 ) ret = 4;
279  else if ( strcmp( envp, "6" ) == 0 ) ret = 6;
280  }
281  return ret;
282 }
283 
284 
285 const char * anonymousIdHeader()
286 {
287  // we need to add the release and identifier to the
288  // agent string.
289  // The target could be not initialized, and then this information
290  // is guessed.
291  static const std::string _value(
293  "X-ZYpp-AnonymousId: %s",
294  Target::anonymousUniqueId( Pathname()/*guess root*/ ).c_str() ) )
295  );
296  return _value.c_str();
297 }
298 
300 {
301  // we need to add the release and identifier to the
302  // agent string.
303  // The target could be not initialized, and then this information
304  // is guessed.
305  static const std::string _value(
307  "X-ZYpp-DistributionFlavor: %s",
308  Target::distributionFlavor( Pathname()/*guess root*/ ).c_str() ) )
309  );
310  return _value.c_str();
311 }
312 
313 const char * agentString()
314 {
315  // we need to add the release and identifier to the
316  // agent string.
317  // The target could be not initialized, and then this information
318  // is guessed.
319  static const std::string _value(
320  str::form(
321  "ZYpp " LIBZYPP_VERSION_STRING " (curl %s) %s"
322  , curl_version_info(CURLVERSION_NOW)->version
323  , Target::targetDistribution( Pathname()/*guess root*/ ).c_str()
324  )
325  );
326  return _value.c_str();
327 }
328 
329 void curlEscape( std::string & str_r,
330  const char char_r, const std::string & escaped_r ) {
331  for ( std::string::size_type pos = str_r.find( char_r );
332  pos != std::string::npos; pos = str_r.find( char_r, pos ) ) {
333  str_r.replace( pos, 1, escaped_r );
334  }
335 }
336 
337 std::string curlEscapedPath( std::string path_r ) {
338  curlEscape( path_r, ' ', "%20" );
339  return path_r;
340 }
341 
342 std::string curlUnEscape( std::string text_r ) {
343  char * tmp = curl_unescape( text_r.c_str(), 0 );
344  std::string ret( tmp );
345  curl_free( tmp );
346  return ret;
347 }
348 
350 {
351  Url curlUrl (url);
352  curlUrl.setUsername( "" );
353  curlUrl.setPassword( "" );
354  curlUrl.setPathParams( "" );
355  curlUrl.setFragment( "" );
356  curlUrl.delQueryParam("cookies");
357  curlUrl.delQueryParam("proxy");
358  curlUrl.delQueryParam("proxyport");
359  curlUrl.delQueryParam("proxyuser");
360  curlUrl.delQueryParam("proxypass");
361  curlUrl.delQueryParam("ssl_capath");
362  curlUrl.delQueryParam("ssl_verify");
363  curlUrl.delQueryParam("ssl_clientcert");
364  curlUrl.delQueryParam("timeout");
365  curlUrl.delQueryParam("auth");
366  curlUrl.delQueryParam("username");
367  curlUrl.delQueryParam("password");
368  curlUrl.delQueryParam("mediahandler");
369  curlUrl.delQueryParam("credentials");
370  curlUrl.delQueryParam("head_requests");
371  return curlUrl;
372 }
373 
374 // bsc#933839: propagate proxy settings passed in the repo URL
375 zypp::Url propagateQueryParams( zypp::Url url_r, const zypp::Url & template_r )
376 {
377  for ( std::string param : { "proxy", "proxyport", "proxyuser", "proxypass"} )
378  {
379  const std::string & value( template_r.getQueryParam( param ) );
380  if ( ! value.empty() )
381  url_r.setQueryParam( param, value );
382  }
383  return url_r;
384 }
385 
386 }
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:18
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:53
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:285
zypp::Url propagateQueryParams(zypp::Url url_r, const zypp::Url &template_r)
Definition: CurlHelper.cc:375
Flag to request encoded string(s).
Definition: UrlUtils.h:53
int getZYPP_MEDIA_CURL_IPRESOLVE()
Definition: CurlHelper.cc:272
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:349
bool useProxyFor(const Url &url_r) const
Return true if enabled and url_r does not match noProxy.
Definition: ProxyInfo.cc:56
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:337
void setHeadRequestsAllowed(bool allowed)
set whether HEAD requests are allowed
std::string username() const
auth username
Url url
Definition: MediaCurl.cc:65
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:299
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:329
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:80
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:101
void setTimeout(long t)
set the transfer timeout
std::string proxy(const Url &url) const
Definition: ProxyInfo.cc:44
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:342
CURL * curl
Definition: MediaCurl.cc:64
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:313
void fillSettingsSystemProxy(const Url &url, media::TransferSettings &s)
Reads the system proxy configuration and fills the settings structure proxy information.
Definition: CurlHelper.cc:249
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:27
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:87
void setProxyEnabled(bool enabled)
whether the proxy is used or not
#define DBG
Definition: Logger.h:78
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