libzypp 17.31.7
curlhelper.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
13
14#include <zypp/APIConfig.h>
15
16#include <zypp-core/fs/PathInfo.h>
17#include <zypp-core/Pathname.h>
18#include <zypp-core/base/Logger.h>
19#include <zypp-core/base/String.h>
20#include <zypp-curl/ProxyInfo>
21#include <zypp-curl/auth/CurlAuthData>
22#include <zypp-media/MediaException>
23#include <list>
24#include <string>
25
26using std::endl;
27using namespace zypp;
28
29namespace zypp
30{
31 namespace env
32 {
33 namespace
34 {
35 inline int getZYPP_MEDIA_CURL_IPRESOLVE()
36 {
37 int ret = 0;
38 if ( const char * envp = getenv( "ZYPP_MEDIA_CURL_IPRESOLVE" ) )
39 {
40 WAR << "env set: $ZYPP_MEDIA_CURL_IPRESOLVE='" << envp << "'" << std::endl;
41 if ( strcmp( envp, "4" ) == 0 ) ret = 4;
42 else if ( strcmp( envp, "6" ) == 0 ) ret = 6;
43 }
44 return ret;
45 }
46 } //namespace
47
49 {
50 static int _v = getZYPP_MEDIA_CURL_IPRESOLVE();
51 return _v;
52 }
53 } // namespace env
54} // namespace zypp
55
56namespace internal
57{
58
60{
61 // function-level static <=> std::call_once
62 static bool once __attribute__ ((__unused__)) = ( [] {
63 if ( curl_global_init( CURL_GLOBAL_ALL ) != 0 )
64 WAR << "curl global init failed" << std::endl;
65 } (), true );
66}
67
68int log_curl(CURL *, curl_infotype info,
69 char *ptr, size_t len, void *max_lvl)
70{
71 if ( max_lvl == nullptr )
72 return 0;
73
74 long maxlvl = *((long *)max_lvl);
75
76 char pfx = ' ';
77 switch( info )
78 {
79 case CURLINFO_TEXT: if ( maxlvl < 1 ) return 0; pfx = '*'; break;
80 case CURLINFO_HEADER_IN: if ( maxlvl < 2 ) return 0; pfx = '<'; break;
81 case CURLINFO_HEADER_OUT: if ( maxlvl < 2 ) return 0; pfx = '>'; break;
82 default:
83 return 0;
84 }
85
86 std::vector<std::string> lines;
87 str::split( std::string(ptr,len), std::back_inserter(lines), "\r\n" );
88 for( const auto & line : lines )
89 {
90 if ( str::startsWith( line, "Authorization:" ) ) {
91 std::string::size_type pos { line.find( " ", 15 ) }; // Authorization: <type> <credentials>
92 if ( pos == std::string::npos )
93 pos = 15;
94 DBG << pfx << " " << line.substr( 0, pos ) << " <credentials removed>" << std::endl;
95 }
96 else
97 DBG << pfx << " " << line << std::endl;
98 }
99 return 0;
100}
101
102size_t log_redirects_curl( char *ptr, size_t size, size_t nmemb, void *userdata)
103{
104 //INT << "got header: " << std::string(ptr, ptr + size*nmemb) << endl;
105
106 char * lstart = ptr, * lend = ptr;
107 size_t pos = 0;
108 size_t max = size * nmemb;
109 while (pos + 1 < max)
110 {
111 // get line
112 for (lstart = lend; *lend != '\n' && pos < max; ++lend, ++pos);
113
114 // look for "Location"
115 if ( strncasecmp( lstart, "Location:", 9 ) == 0 )
116 {
117 std::string line { lstart, *(lend-1)=='\r' ? lend-1 : lend };
118 DBG << "redirecting to " << line << std::endl;
119 if ( userdata ) {
120 *reinterpret_cast<std::string *>( userdata ) = line;
121 }
122 return max;
123 }
124
125 // continue with the next line
126 if (pos + 1 < max)
127 {
128 ++lend;
129 ++pos;
130 }
131 else
132 break;
133 }
134
135 return max;
136}
137
143{
144 {
145 const std::string & param { url.getQueryParam("timeout") };
146 if( ! param.empty() )
147 {
148 long num = str::strtonum<long>(param);
149 if( num >= 0 && num <= TRANSFER_TIMEOUT_MAX )
150 s.setTimeout( num );
151 }
152 }
153 {
154 std::string param { url.getUsername() };
155 if ( ! param.empty() )
156 {
157 s.setUsername( std::move(param) );
158 param = url.getPassword();
159 if ( ! param.empty() )
160 s.setPassword( std::move(param) );
161 }
162 else
163 {
164 // if there is no username, set anonymous auth
165 if ( ( url.getScheme() == "ftp" || url.getScheme() == "tftp" ) && s.username().empty() )
167 }
168 }
169 if ( url.getScheme() == "https" )
170 {
171 s.setVerifyPeerEnabled( false );
172 s.setVerifyHostEnabled( false );
173
174 const std::string & verify { url.getQueryParam("ssl_verify") };
175 if( verify.empty() || verify == "yes" )
176 {
177 s.setVerifyPeerEnabled( true );
178 s.setVerifyHostEnabled( true );
179 }
180 else if ( verify == "no" )
181 {
182 s.setVerifyPeerEnabled( false );
183 s.setVerifyHostEnabled( false );
184 }
185 else
186 {
187 std::vector<std::string> flags;
188 str::split( verify, std::back_inserter(flags), "," );
189 for ( const auto & flag : flags )
190 {
191 if ( flag == "host" )
192 s.setVerifyHostEnabled( true );
193 else if ( flag == "peer" )
194 s.setVerifyPeerEnabled( true );
195 else
196 ZYPP_THROW( media::MediaBadUrlException(url, "Unknown ssl_verify flag "+flag) );
197 }
198 }
199 }
200 {
201 Pathname ca_path { url.getQueryParam("ssl_capath") };
202 if( ! ca_path.empty() )
203 {
204 if( ! PathInfo(ca_path).isDir() || ! ca_path.absolute() )
205 ZYPP_THROW(media::MediaBadUrlException(url, "Invalid ssl_capath path"));
206 else
207 s.setCertificateAuthoritiesPath( std::move(ca_path) );
208 }
209 }
210 {
211 Pathname client_cert { url.getQueryParam("ssl_clientcert") };
212 if( ! client_cert.empty() )
213 {
214 if( ! PathInfo(client_cert).isFile() || ! client_cert.absolute() )
215 ZYPP_THROW(media::MediaBadUrlException(url, "Invalid ssl_clientcert file"));
216 else
217 s.setClientCertificatePath( std::move(client_cert) );
218 }
219 }
220 {
221 Pathname client_key { url.getQueryParam("ssl_clientkey") };
222 if( ! client_key.empty() )
223 {
224 if( ! PathInfo(client_key).isFile() || ! client_key.absolute() )
225 ZYPP_THROW(media::MediaBadUrlException(url, "Invalid ssl_clientkey file"));
226 else
227 s.setClientKeyPath( std::move(client_key) );
228 }
229 }
230 {
231 std::string param { url.getQueryParam( "proxy" ) };
232 if ( ! param.empty() )
233 {
234 if ( param == EXPLICITLY_NO_PROXY ) {
235 // Workaround TransferSettings shortcoming: With an
236 // empty proxy string, code will continue to look for
237 // valid proxy settings. So set proxy to some non-empty
238 // string, to indicate it has been explicitly disabled.
240 s.setProxyEnabled(false);
241 }
242 else {
243 const std::string & proxyport { url.getQueryParam( "proxyport" ) };
244 if ( ! proxyport.empty() ) {
245 param += ":";
246 param += proxyport;
247 }
248 s.setProxy( std::move(param) );
249 s.setProxyEnabled( true );
250 }
251 }
252 }
253 {
254 std::string param { url.getQueryParam( "proxyuser" ) };
255 if ( ! param.empty() )
256 {
257 s.setProxyUsername( std::move(param) );
258 s.setProxyPassword( url.getQueryParam( "proxypass" ) );
259 }
260 }
261 {
262 // HTTP authentication type
263 std::string param { url.getQueryParam("auth") };
264 if ( ! param.empty() && (url.getScheme() == "http" || url.getScheme() == "https") )
265 {
266 try
267 {
268 media::CurlAuthData::auth_type_str2long (param ); // check if we know it
269 }
270 catch ( const media::MediaException & ex_r )
271 {
272 DBG << "Rethrowing as MediaUnauthorizedException.";
274 }
275 s.setAuthType( std::move(param) );
276 }
277 }
278 {
279 // workarounds
280 const std::string & param { url.getQueryParam("head_requests") };
281 if( ! param.empty() && param == "no" )
282 s.setHeadRequestsAllowed( false );
283 }
284}
285
291{
292 media::ProxyInfo proxy_info;
293 if ( proxy_info.useProxyFor( url ) )
294 {
295 // We must extract any 'user:pass' from the proxy url
296 // otherwise they won't make it into curl (.curlrc wins).
297 try {
298 Url u( proxy_info.proxy( url ) );
299 s.setProxy( u.asString( url::ViewOption::WITH_SCHEME + url::ViewOption::WITH_HOST + url::ViewOption::WITH_PORT ) );
300 // don't overwrite explicit auth settings
301 if ( s.proxyUsername().empty() )
302 {
305 }
306 s.setProxyEnabled( true );
307 }
308 catch (...) {} // no proxy if URL is malformed
309 }
310}
311
312void curlEscape( std::string & str_r,
313 const char char_r, const std::string & escaped_r ) {
314 for ( std::string::size_type pos = str_r.find( char_r );
315 pos != std::string::npos; pos = str_r.find( char_r, pos ) ) {
316 str_r.replace( pos, 1, escaped_r );
317 }
318}
319
320std::string curlEscapedPath( std::string path_r ) {
321 curlEscape( path_r, ' ', "%20" );
322 return path_r;
323}
324
325std::string curlUnEscape( std::string text_r ) {
326 char * tmp = curl_unescape( text_r.c_str(), 0 );
327 std::string ret( tmp );
328 curl_free( tmp );
329 return ret;
330}
331
333{
334 Url curlUrl (url);
335 curlUrl.setUsername( "" );
336 curlUrl.setPassword( "" );
337 curlUrl.setPathParams( "" );
338 curlUrl.setFragment( "" );
339 curlUrl.delQueryParam("cookies");
340 curlUrl.delQueryParam("proxy");
341 curlUrl.delQueryParam("proxyport");
342 curlUrl.delQueryParam("proxyuser");
343 curlUrl.delQueryParam("proxypass");
344 curlUrl.delQueryParam("ssl_capath");
345 curlUrl.delQueryParam("ssl_verify");
346 curlUrl.delQueryParam("ssl_clientcert");
347 curlUrl.delQueryParam("timeout");
348 curlUrl.delQueryParam("auth");
349 curlUrl.delQueryParam("username");
350 curlUrl.delQueryParam("password");
351 curlUrl.delQueryParam("mediahandler");
352 curlUrl.delQueryParam("credentials");
353 curlUrl.delQueryParam("head_requests");
354 return curlUrl;
355}
356
357// bsc#933839: propagate proxy settings passed in the repo URL
359{
360 using namespace std::literals::string_literals;
361 for ( const std::string &param : { "proxy"s, "proxyport"s, "proxyuser"s, "proxypass"s} )
362 {
363 const std::string & value( template_r.getQueryParam( param ) );
364 if ( ! value.empty() )
365 url_r.setQueryParam( param, value );
366 }
367 return url_r;
368}
369
370}
const std::string & msg() const
Return the message string provided to the ctor.
Definition: Exception.h:195
Url manipulation class.
Definition: Url.h:92
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:533
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:497
std::string getUsername(EEncoding eflag=zypp::url::E_DECODED) const
Returns the username from the URL authority.
Definition: Url.cc:572
void setFragment(const std::string &fragment, EEncoding eflag=zypp::url::E_DECODED)
Set the fragment string in the URL.
Definition: Url.cc:722
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:660
void delQueryParam(const std::string &param)
remove the specified query parameter.
Definition: Url.cc:845
void setPassword(const std::string &pass, EEncoding eflag=zypp::url::E_DECODED)
Set the password in the URL authority.
Definition: Url.cc:739
void setPathParams(const std::string &params)
Set the path parameters.
Definition: Url.cc:791
void setQueryParam(const std::string &param, const std::string &value)
Set or add value for the specified query parameter.
Definition: Url.cc:838
void setUsername(const std::string &user, EEncoding eflag=zypp::url::E_DECODED)
Set the username in the URL authority.
Definition: Url.cc:730
std::string getPassword(EEncoding eflag=zypp::url::E_DECODED) const
Returns the password from the URL authority.
Definition: Url.cc:580
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
Just inherits Exception to separate media exceptions.
bool useProxyFor(const Url &url_r) const
Return true if enabled and url_r does not match noProxy.
Definition: proxyinfo.cc:55
std::string proxy(const Url &url) const
Definition: proxyinfo.cc:43
Holds transfer setting.
void setProxy(const std::string &val_r)
proxy to use if it is enabled
void setProxyEnabled(bool enabled)
whether the proxy is used or not
void setUsername(const std::string &val_r)
sets the auth username
void setProxyUsername(const std::string &val_r)
sets the proxy user
void setHeadRequestsAllowed(bool allowed)
set whether HEAD requests are allowed
void setVerifyHostEnabled(bool enabled)
Sets whether to verify host for ssl.
void setClientKeyPath(const Pathname &val_r)
Sets the SSL client key file.
void setClientCertificatePath(const Pathname &val_r)
Sets the SSL client certificate file.
void setPassword(const std::string &val_r)
sets the auth password
void setVerifyPeerEnabled(bool enabled)
Sets whether to verify host for ssl.
void setAnonymousAuth()
sets anonymous authentication (ie: for ftp)
const std::string & username() const
auth username
const std::string & proxyUsername() const
proxy auth username
void setAuthType(const std::string &val_r)
set the allowed authentication types
void setCertificateAuthoritiesPath(const Pathname &val_r)
Sets the SSL certificate authorities path.
void setProxyPassword(const std::string &val_r)
sets the proxy password
void setTimeout(long t)
set the transfer timeout
#define TRANSFER_TIMEOUT_MAX
Definition: curlhelper_p.h:22
#define EXPLICITLY_NO_PROXY
Definition: curlhelper_p.h:25
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:142
size_t log_redirects_curl(char *ptr, size_t size, size_t nmemb, void *userdata)
Definition: curlhelper.cc:102
void globalInitCurlOnce()
Definition: curlhelper.cc:59
zypp::Url propagateQueryParams(zypp::Url url_r, const zypp::Url &template_r)
Definition: curlhelper.cc:358
std::string curlUnEscape(std::string text_r)
Definition: curlhelper.cc:325
std::string curlEscapedPath(std::string path_r)
Definition: curlhelper.cc:320
void fillSettingsSystemProxy(const Url &url, media::TransferSettings &s)
Reads the system proxy configuration and fills the settings structure proxy information.
Definition: curlhelper.cc:290
Url clearQueryString(const Url &url)
Definition: curlhelper.cc:332
int log_curl(CURL *, curl_infotype info, char *ptr, size_t len, void *max_lvl)
Definition: curlhelper.cc:68
void curlEscape(std::string &str_r, const char char_r, const std::string &escaped_r)
Definition: curlhelper.cc:312
int ZYPP_MEDIA_CURL_IPRESOLVE()
4/6 to force IPv4/v6
Definition: curlhelper.cc:48
SolvableIdType size_type
Definition: PoolMember.h:126
bool startsWith(const C_Str &str_r, const C_Str &prefix_r)
alias for hasPrefix
Definition: String.h:1085
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:531
@ E_ENCODED
Flag to request encoded string(s).
Definition: UrlUtils.h:53
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:428
#define DBG
Definition: Logger.h:95
#define WAR
Definition: Logger.h:97