21#include <zypp-curl/ProxyInfo> 
   22#include <zypp-curl/auth/CurlAuthData> 
   23#include <zypp-media/MediaException> 
   27#define  TRANSFER_TIMEOUT_MAX   60 * 60 
   38      static const long ret = [](){
 
   39        const char * 
env = getenv(
"ZYPP_MEDIA_CURL_DEBUG");
 
 
   49        if ( 
const char * envp = getenv( 
"ZYPP_MEDIA_CURL_IPRESOLVE" ) ) {
 
   50          WAR << 
"env set: $ZYPP_MEDIA_CURL_IPRESOLVE='" << envp << 
"'" << std::endl;
 
   51          if (      strcmp( envp, 
"4" ) == 0 )  ret = 4;
 
   52          else if ( strcmp( envp, 
"6" ) == 0 )  ret = 6;
 
 
   67  static bool once __attribute__ ((__unused__)) = ( [] {
 
   68    MIL << 
"global_init libcurl: build version: (" << LIBCURL_VERSION << 
"), runtime version: (" << curl_version_info(CURLVERSION_NOW)->version << 
") " << endl;
 
   69    if ( curl_global_init( CURL_GLOBAL_ALL ) != 0 )
 
   70      WAR << 
"curl global init failed" << std::endl;
 
 
   76  auto curlV = curl_version_info ( CURLVERSION_NOW );
 
   77  return curlV->version_num;
 
 
   80int log_curl( CURL * curl, curl_infotype info, 
char * ptr, 
size_t len, 
void * max_lvl )
 
   82  if ( max_lvl == 
nullptr )
 
   85  long maxlvl = *(
static_cast<long*
>(max_lvl));
 
   86  const char * pfx = 
"";
 
   87  bool isContent = 
true;  
 
   90    case CURLINFO_TEXT:         
if ( maxlvl < 1 ) 
return 0; pfx = 
"*"; 
break;
 
   91    case CURLINFO_HEADER_IN:    
if ( maxlvl < 2 ) 
return 0; pfx = 
"<"; 
break;
 
   92    case CURLINFO_HEADER_OUT:   
if ( maxlvl < 2 ) 
return 0; pfx = 
">"; 
break;
 
   93    case CURLINFO_SSL_DATA_IN:  
if ( maxlvl < 3 ) 
return 0; isContent = 
false; pfx = 
"<[SSL]"; 
break;
 
   94    case CURLINFO_SSL_DATA_OUT: 
if ( maxlvl < 3 ) 
return 0; isContent = 
false; pfx = 
">[SSL]"; 
break;
 
   95    case CURLINFO_DATA_IN:      
if ( maxlvl < 3 ) 
return 0; isContent = 
false; pfx = 
"<[DTA]"; 
break;
 
   96    case CURLINFO_DATA_OUT:     
if ( maxlvl < 3 ) 
return 0; isContent = 
false; pfx = 
">[DTA]"; 
break;
 
  105    std::vector<std::string_view> lines;  
 
  106    strv::split( std::string_view( ptr, len ), 
"\n", [&lines]( std::string_view line, 
unsigned, 
bool last ) {
 
  108      line = strv::rtrim( line, 
"\r" );
 
  109      lines.push_back( line );
 
  111    for ( 
const auto & line : lines ) {
 
  113        std::string_view::size_type pos { line.find( 
" ", 15 ) }; 
 
  114        if ( pos == std::string::npos )
 
  116        DBG << curl << 
" " << pfx << 
" " << line.substr( 0, pos ) << 
" <credentials removed>" << endl;
 
  119        DBG << curl << 
" " << pfx << 
" " << line << endl;
 
  123      DBG << curl << 
" " << pfx << 
" " << len << 
" byte" << endl;
 
  125      hexdumpOn( 
DBG << curl << 
" " << pfx << 
" ", ptr, len );
 
 
  133    INT << 
"Got a NULL curl handle" << endl;
 
  137    curl_easy_setopt( curl, CURLOPT_VERBOSE, 1L );
 
  138    curl_easy_setopt( curl, CURLOPT_DEBUGFUNCTION, 
log_curl );
 
 
  147  char * lstart = ptr, * lend = ptr;
 
  149  size_t max = size * nmemb;
 
  150  while (pos + 1 < max)
 
  153    for (lstart = lend; *lend != 
'\n' && pos < max; ++lend, ++pos);
 
  156    if ( strncasecmp( lstart, 
"Location:", 9 ) == 0 )
 
  158      std::string line { lstart, *(lend-1)==
'\r' ? lend-1 : lend };
 
  159      DBG << 
"redirecting to " << line << std::endl;
 
  161        *
reinterpret_cast<std::string *
>( userdata ) = line;
 
 
  186    const std::string & param { 
url.getQueryParam(
"timeout") };
 
  187    if( ! param.empty() )
 
  195    std::string param { 
url.getUsername() };
 
  196    if ( ! param.empty() )
 
  199      param = 
url.getPassword();
 
  200      if ( ! param.empty() )
 
  206      if ( ( 
url.getScheme() == 
"ftp" || 
url.getScheme() == 
"tftp" ) && s.
username().empty() )
 
  210  if ( 
url.getScheme() == 
"https" )
 
  215    const std::string & verify { 
url.getQueryParam(
"ssl_verify") };
 
  216    if( verify.empty() || verify == 
"yes" )
 
  221    else if ( verify == 
"no" )
 
  228      std::vector<std::string> flags;
 
  229      str::split( verify, std::back_inserter(flags), 
"," );
 
  230      for ( 
const auto & flag : flags )
 
  232        if ( flag == 
"host" )
 
  234        else if ( flag == 
"peer" )
 
  242    Pathname ca_path { 
url.getQueryParam(
"ssl_capath") };
 
  243    if( ! ca_path.empty() )
 
  245      if( ! 
PathInfo(ca_path).isDir() || ! ca_path.absolute() )
 
  252    Pathname client_cert { 
url.getQueryParam(
"ssl_clientcert") };
 
  253    if( ! client_cert.empty() )
 
  255      if( ! 
PathInfo(client_cert).isFile() || ! client_cert.absolute() )
 
  262    Pathname client_key { 
url.getQueryParam(
"ssl_clientkey") };
 
  263    if( ! client_key.empty() )
 
  265      if( ! 
PathInfo(client_key).isFile() || ! client_key.absolute() )
 
  272    std::string param { 
url.getQueryParam( 
"proxy" ) };
 
  273    if ( ! param.empty() )
 
  284        const std::string & proxyport { 
url.getQueryParam( 
"proxyport" ) };
 
  285        if ( ! proxyport.empty() ) {
 
  295    std::string param { 
url.getQueryParam( 
"proxyuser" ) };
 
  296    if ( ! param.empty() )
 
  304    std::string param { 
url.getQueryParam(
"auth") };
 
  305    if ( ! param.empty() && (
url.getScheme() == 
"http" || 
url.getScheme() == 
"https") )
 
  313        DBG << 
"Rethrowing as MediaUnauthorizedException.";
 
  321    const std::string & param { 
url.getQueryParam(
"head_requests") };
 
  322    if( ! param.empty() && param == 
"no" )
 
  326    const auto &cookieFileParam = 
url.getQueryParam( 
"cookies" );
 
  327    if ( !cookieFileParam.empty() && 
str::strToBool( cookieFileParam, 
true ) )
 
 
  347      s.
setProxy( u.
asString( url::ViewOption::WITH_SCHEME + url::ViewOption::WITH_HOST + url::ViewOption::WITH_PORT ) );
 
 
  361  const char char_r, 
const std::string & escaped_r ) {
 
  362  for ( std::string::size_type pos = str_r.find( char_r );
 
  363        pos != std::string::npos; pos = str_r.find( char_r, pos ) ) {
 
  364    str_r.replace( pos, 1, escaped_r );
 
 
  374  char * tmp = curl_unescape( text_r.c_str(), 0 );
 
  375  std::string ret( tmp );
 
 
  413  using namespace std::literals::string_literals;
 
  414  for ( 
const std::string ¶m : { 
"proxy"s, 
"proxyport"s, 
"proxyuser"s, 
"proxypass"s, 
"ssl_capath"s, 
"ssl_verify"s } )
 
  416    const std::string & value( template_r.
getQueryParam( param ) );
 
  417    if ( ! value.empty() )
 
 
  424  curl_multi_setopt( 
_parent._multi, CURLMOPT_SOCKETFUNCTION, 
socketcb );
 
  425  curl_multi_setopt( 
_parent._multi, CURLMOPT_SOCKETDATA, 
this );
 
  426  curl_multi_setopt( 
_parent._multi, CURLMOPT_TIMERFUNCTION, 
timercb );
 
  427  curl_multi_setopt( 
_parent._multi, CURLMOPT_TIMERDATA, 
this );
 
 
  431  curl_multi_setopt( 
_parent._multi, CURLMOPT_SOCKETFUNCTION, 
nullptr );
 
  432  curl_multi_setopt( 
_parent._multi, CURLMOPT_SOCKETDATA, 
nullptr );
 
  433  curl_multi_setopt( 
_parent._multi, CURLMOPT_TIMERFUNCTION, 
nullptr );
 
  434  curl_multi_setopt( 
_parent._multi, CURLMOPT_TIMERDATA, 
nullptr );
 
 
  438  auto it = std::find_if( userp->
socks.begin(), userp->
socks.end(), [&]( 
const GPollFD &fd){ return fd.fd == s; });
 
  440  if ( what == CURL_POLL_REMOVE ) {
 
  441    if ( it == userp->
socks.end() ) {
 
  442      WAR << 
"Ignoring unknown socket in static_socketcb" << std::endl;
 
  445    userp->
socks.erase(it);
 
  447  } 
else if ( what == CURL_POLL_IN ) {
 
  448    events = G_IO_IN | G_IO_HUP | G_IO_ERR;
 
  449  } 
else if ( what == CURL_POLL_OUT ) {
 
  450    events = G_IO_OUT | G_IO_ERR;
 
  451  } 
else if ( what == CURL_POLL_INOUT ) {
 
  452    events = G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR;
 
  455  if ( it != userp->
socks.end() ) {
 
  459    userp->
socks.push_back(
 
 
  482  for ( 
size_t sock = first; sock < actionsFds.size(); sock++ ) {
 
  483    const auto &waitFd = actionsFds[sock];
 
  484    if ( waitFd.revents == 0 )
 
  488    if ( (waitFd.revents & G_IO_HUP) == G_IO_HUP
 
  489        || (waitFd.revents & G_IO_IN) == G_IO_IN ) {
 
  490      ev = CURL_CSELECT_IN;
 
  492    if ( (waitFd.revents & G_IO_OUT) == G_IO_OUT ) {
 
  493      ev |= CURL_CSELECT_OUT;
 
  495    if ( (waitFd.revents & G_IO_ERR) == G_IO_ERR ) {
 
  496      ev |= CURL_CSELECT_ERR;
 
  500    CURLMcode mcode = curl_multi_socket_action( 
_parent._multi, waitFd.fd, ev, &runn );
 
  501    if (mcode != CURLM_OK)
 
 
  510  return curl_multi_socket_action( 
_parent._multi, CURL_SOCKET_TIMEOUT, 0, &handles );
 
 
  525#if CURLVERSION_AT_LEAST(7,19,4) 
  526#if CURLVERSION_AT_LEAST(7,85,0) 
  529    return curl_easy_setopt ( curl, CURLOPT_REDIR_PROTOCOLS_STR, 
"https" );
 
  531    return curl_easy_setopt ( curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS );
 
  534  return curl_easy_setopt ( curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS );
 
 
const std::string & msg() const
Return the message string provided to the ctor.
void delQueryParams(const std::set< std::string > ¶ms)
remove multiple query parameters at once
std::string asString() const
Returns a default string representation of the Url object.
std::string getUsername(EEncoding eflag=zypp::url::E_DECODED) const
Returns the username from the URL authority.
void setFragment(const std::string &fragment, EEncoding eflag=zypp::url::E_DECODED)
Set the fragment string in the URL.
std::string getQueryParam(const std::string ¶m, EEncoding eflag=zypp::url::E_DECODED) const
Return the value for the specified query parameter.
void setPassword(const std::string &pass, EEncoding eflag=zypp::url::E_DECODED)
Set the password in the URL authority.
void setPathParams(const std::string ¶ms)
Set the path parameters.
void setQueryParam(const std::string ¶m, const std::string &value)
Set or add value for the specified query parameter.
void setUsername(const std::string &user, EEncoding eflag=zypp::url::E_DECODED)
Set the username in the URL authority.
std::string getPassword(EEncoding eflag=zypp::url::E_DECODED) const
Returns the password from the URL authority.
Wrapper class for stat/lstat.
#define TRANSFER_TIMEOUT_MAX
#define EXPLICITLY_NO_PROXY
void fillSettingsFromUrl(const Url &url, media::TransferSettings &s)
Fills the settings structure using options passed on the url for example ?timeout=x&proxy=foo.
size_t log_redirects_curl(char *ptr, size_t size, size_t nmemb, void *userdata)
void globalInitCurlOnce()
zypp::Url propagateQueryParams(zypp::Url url_r, const zypp::Url &template_r)
std::string curlUnEscape(const std::string &text_r)
void setupZYPP_MEDIA_CURL_DEBUG(CURL *curl)
Setup CURLOPT_VERBOSE and CURLOPT_DEBUGFUNCTION according to env::ZYPP_MEDIA_CURL_DEBUG.
std::string curlEscapedPath(std::string path_r)
CURLcode setCurlRedirProtocols(CURL *curl)
void fillSettingsSystemProxy(const Url &url, media::TransferSettings &s)
Reads the system proxy configuration and fills the settings structure proxy information.
Url clearQueryString(const Url &url)
void curlEscape(std::string &str_r, const char char_r, const std::string &escaped_r)
int log_curl(CURL *curl, curl_infotype info, char *ptr, size_t len, void *max_lvl)
Namespace intended to collect all environment variables we use.
const long & ZYPP_MEDIA_CURL_DEBUG()
const long& for setting CURLOPT_DEBUGDATA Returns a reference to a static variable,...
int ZYPP_MEDIA_CURL_IPRESOLVE()
4/6 to force IPv4/v6
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
bool strToBool(const C_Str &str, bool default_r)
Parse str into a bool depending on the default value.
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.
TInt strtonum(const C_Str &str)
Parsing numbers from string.
@ E_ENCODED
Flag to request encoded string(s).
Easy-to use interface to the ZYPP dependency resolver.
std::ostream & hexdumpOn(std::ostream &outs, const unsigned char *ptr, size_t size)
hexdump data on stream
static int socketcb(CURL *easy, curl_socket_t s, int what, CurlPollHelper *userp, void *sockp)
CurlPollHelper(CurlPoll &p)
CURLMcode handleSocketActions(const std::vector< GPollFD > &actionsFds, int first=0)
std::vector< GPollFD > socks
std::optional< long > timeout_ms
static int timercb(CURLM *, long timeout_ms, CurlPollHelper *thatPtr)
Provides API related macros.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.