libzypp  17.23.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  std::string pfx(" ");
32  long lvl = 0;
33  switch( info)
34  {
35  case CURLINFO_TEXT: lvl = 1; pfx = "*"; break;
36  case CURLINFO_HEADER_IN: lvl = 2; pfx = "<"; break;
37  case CURLINFO_HEADER_OUT: lvl = 2; pfx = ">"; break;
38  default: break;
39  }
40  if( lvl > 0 && max_lvl != NULL && lvl <= *((long *)max_lvl))
41  {
42  std::string msg(ptr, len);
43  std::list<std::string> lines;
44  std::list<std::string>::const_iterator line;
45  zypp::str::split(msg, std::back_inserter(lines), "\r\n");
46  for(line = lines.begin(); line != lines.end(); ++line)
47  {
48  DBG << pfx << " " << *line << std::endl;
49  }
50  }
51  return 0;
52 }
53 
54 size_t log_redirects_curl( char *ptr, size_t size, size_t nmemb, void *userdata)
55 {
56  // INT << "got header: " << string(ptr, ptr + size*nmemb) << endl;
57 
58  char * lstart = ptr, * lend = ptr;
59  size_t pos = 0;
60  size_t max = size * nmemb;
61  while (pos + 1 < max)
62  {
63  // get line
64  for (lstart = lend; *lend != '\n' && pos < max; ++lend, ++pos);
65 
66  // look for "Location"
67  if ( lstart[0] == 'L'
68  && lstart[1] == 'o'
69  && lstart[2] == 'c'
70  && lstart[3] == 'a'
71  && lstart[4] == 't'
72  && lstart[5] == 'i'
73  && lstart[6] == 'o'
74  && lstart[7] == 'n'
75  && lstart[8] == ':' )
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 }
internal::curlUnEscape
std::string curlUnEscape(std::string text_r)
Definition: CurlHelper.cc:343
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::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:35
internal::agentString
const char * agentString()
initialized only once, this gets the agent string which also includes the curl version
Definition: CurlHelper.cc:314
zypp::media::ProxyInfo
Definition: ProxyInfo.h:29
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:269
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:250
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::filesystem::PathInfo::isDir
bool isDir() const
Definition: PathInfo.h:290
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:286
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:20
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:102
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:220
internal::curlEscapedPath
std::string curlEscapedPath(std::string path_r)
Definition: CurlHelper.cc:338
internal::clearQueryString
Url clearQueryString(const Url &url)
Definition: CurlHelper.cc:350
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::filesystem::PathInfo::isFile
bool isFile() const
Definition: PathInfo.h:289
zypp::media::MediaUnauthorizedException
Definition: MediaException.h:427
zypp::str::form
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:35
internal::curlEscape
void curlEscape(std::string &str_r, const char char_r, const std::string &escaped_r)
Definition: CurlHelper.cc:330
internal::env::getZYPP_MEDIA_CURL_IPRESOLVE
int getZYPP_MEDIA_CURL_IPRESOLVE()
Definition: CurlHelper.cc:273
MediaException.h
zypp
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
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:376
zypp::url::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:300
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:44
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:16
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
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:87
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:54
zypp::str::trim
std::string trim(const std::string &s, const Trim trim_r)
Definition: String.cc:216
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