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;
185 if ( s.
proxy().empty() )
199 const std::string & param {
url.getQueryParam(
"timeout") };
200 if( ! param.empty() )
208 std::string param {
url.getUsername() };
209 if ( ! param.empty() )
212 param =
url.getPassword();
213 if ( ! param.empty() )
219 if ( (
url.getScheme() ==
"ftp" ||
url.getScheme() ==
"tftp" ) && s.
username().empty() )
223 if (
url.getScheme() ==
"https" )
228 const std::string & verify {
url.getQueryParam(
"ssl_verify") };
229 if( verify.empty() || verify ==
"yes" )
234 else if ( verify ==
"no" )
241 std::vector<std::string> flags;
242 str::split( verify, std::back_inserter(flags),
"," );
243 for (
const auto & flag : flags )
245 if ( flag ==
"host" )
247 else if ( flag ==
"peer" )
255 Pathname ca_path {
url.getQueryParam(
"ssl_capath") };
256 if( ! ca_path.
empty() )
265 Pathname client_cert {
url.getQueryParam(
"ssl_clientcert") };
266 if( ! client_cert.
empty() )
275 Pathname client_key {
url.getQueryParam(
"ssl_clientkey") };
276 if( ! client_key.
empty() )
285 std::string param {
url.getQueryParam(
"proxy" ) };
286 if ( ! param.empty() )
297 const std::string & proxyport {
url.getQueryParam(
"proxyport" ) };
298 if ( ! proxyport.empty() ) {
308 std::string param {
url.getQueryParam(
"proxyuser" ) };
309 if ( ! param.empty() )
317 std::string param {
url.getQueryParam(
"auth") };
318 if ( ! param.empty() && (
url.getScheme() ==
"http" ||
url.getScheme() ==
"https") )
326 DBG <<
"Rethrowing as MediaUnauthorizedException.";
334 const std::string & param {
url.getQueryParam(
"head_requests") };
335 if( ! param.empty() && param ==
"no" )
339 const auto &cookieFileParam =
url.getQueryParam(
"cookies" );
340 if ( !cookieFileParam.empty() &&
str::strToBool( cookieFileParam,
true ) )
360 s.
setProxy( u.
asString( url::ViewOption::WITH_SCHEME + url::ViewOption::WITH_HOST + url::ViewOption::WITH_PORT ) );
374 const char char_r,
const std::string & escaped_r ) {
375 for ( std::string::size_type pos = str_r.find( char_r );
376 pos != std::string::npos; pos = str_r.find( char_r, pos ) ) {
377 str_r.replace( pos, 1, escaped_r );
387 char * tmp = curl_unescape( text_r.c_str(), 0 );
388 std::string ret( tmp );
426 using namespace std::literals::string_literals;
427 for (
const std::string ¶m : {
"proxy"s,
"proxyport"s,
"proxyuser"s,
"proxypass"s,
"ssl_capath"s,
"ssl_verify"s } )
429 const std::string & value( template_r.
getQueryParam( param ) );
430 if ( ! value.empty() )
437 curl_multi_setopt(
_parent._multi, CURLMOPT_SOCKETFUNCTION,
socketcb );
438 curl_multi_setopt(
_parent._multi, CURLMOPT_SOCKETDATA,
this );
439 curl_multi_setopt(
_parent._multi, CURLMOPT_TIMERFUNCTION,
timercb );
440 curl_multi_setopt(
_parent._multi, CURLMOPT_TIMERDATA,
this );
444 curl_multi_setopt(
_parent._multi, CURLMOPT_SOCKETFUNCTION,
nullptr );
445 curl_multi_setopt(
_parent._multi, CURLMOPT_SOCKETDATA,
nullptr );
446 curl_multi_setopt(
_parent._multi, CURLMOPT_TIMERFUNCTION,
nullptr );
447 curl_multi_setopt(
_parent._multi, CURLMOPT_TIMERDATA,
nullptr );
451 auto it = std::find_if( userp->
socks.begin(), userp->
socks.end(), [&](
const GPollFD &fd){ return fd.fd == s; });
453 if ( what == CURL_POLL_REMOVE ) {
454 if ( it == userp->
socks.end() ) {
455 WAR <<
"Ignoring unknown socket in static_socketcb" << std::endl;
458 userp->
socks.erase(it);
460 }
else if ( what == CURL_POLL_IN ) {
461 events = G_IO_IN | G_IO_HUP | G_IO_ERR;
462 }
else if ( what == CURL_POLL_OUT ) {
463 events = G_IO_OUT | G_IO_ERR;
464 }
else if ( what == CURL_POLL_INOUT ) {
465 events = G_IO_IN | G_IO_OUT | G_IO_HUP | G_IO_ERR;
468 if ( it != userp->
socks.end() ) {
472 userp->
socks.push_back(
495 for (
size_t sock = first; sock < actionsFds.size(); sock++ ) {
496 const auto &waitFd = actionsFds[sock];
497 if ( waitFd.revents == 0 )
501 if ( (waitFd.revents & G_IO_HUP) == G_IO_HUP
502 || (waitFd.revents & G_IO_IN) == G_IO_IN ) {
503 ev = CURL_CSELECT_IN;
505 if ( (waitFd.revents & G_IO_OUT) == G_IO_OUT ) {
506 ev |= CURL_CSELECT_OUT;
508 if ( (waitFd.revents & G_IO_ERR) == G_IO_ERR ) {
509 ev |= CURL_CSELECT_ERR;
513 CURLMcode mcode = curl_multi_socket_action(
_parent._multi, waitFd.fd, ev, &runn );
514 if (mcode != CURLM_OK)
523 return curl_multi_socket_action(
_parent._multi, CURL_SOCKET_TIMEOUT, 0, &handles );
538#if CURLVERSION_AT_LEAST(7,19,4)
539#if CURLVERSION_AT_LEAST(7,85,0)
542 return curl_easy_setopt ( curl, CURLOPT_REDIR_PROTOCOLS_STR,
"https" );
544 return curl_easy_setopt ( curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS );
547 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.
bool absolute() const
Test for an absolute path.
bool empty() const
Test for an empty path.
#define TRANSFER_TIMEOUT_MAX
#define EXPLICITLY_NO_PROXY
void prepareSettingsAndUrl(zypp::Url &url_r, zypp::media::TransferSettings &s)
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.