libzypp 17.34.1
proxyinfolibproxy.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
14#include <iostream>
15#include <optional>
16
19#include <zypp-core/fs/WatchFile>
20#include <zypp-core/Pathname.h>
21
22#include <zypp-curl/proxyinfo/ProxyInfoLibproxy>
23
24#include <dlfcn.h> // for dlload, dlsym, dlclose
25#include <glib.h> // g_clear_pointer and g_strfreev
26
27using std::endl;
28using namespace zypp::base;
29
30namespace zypp {
31 namespace media {
32
33 namespace {
34
35 using CreateFactoryCb = CreateFactorySig<pxProxyFactoryType>;
36 using DelFactoryCb = DelFactorySig<pxProxyFactoryType>;
37 using GetProxiesCb = GetProxiesSig<pxProxyFactoryType>;
38
39 struct LibProxyAPI
40 {
42 CreateFactoryCb createProxyFactory = nullptr;
43 DelFactoryCb deleteProxyFactory = nullptr;
44 GetProxiesCb getProxies = nullptr;
46
52 static void fallbackFreeProxies( char **proxies ) {
53 g_clear_pointer (&proxies, g_strfreev);
54 }
55
56 static std::unique_ptr<LibProxyAPI> create() {
57 MIL << "Detecting libproxy availability" << std::endl;
58 zypp::AutoDispose<void *> handle( dlopen("libproxy.so.1", RTLD_LAZY ), []( void *ptr ){ if ( ptr ) ::dlclose(ptr); });
59 if ( !handle ) {
60 MIL << "No libproxy support detected (could not load library): " << dlerror() << std::endl;
61 return nullptr;
62 }
63
64 std::unique_ptr<LibProxyAPI> apiInstance = std::make_unique<LibProxyAPI>();
65 apiInstance->libProxyLibHandle = std::move(handle);
66 apiInstance->createProxyFactory = (CreateFactoryCb)::dlsym ( apiInstance->libProxyLibHandle, "px_proxy_factory_new" );
67 if ( !apiInstance->createProxyFactory ){
68 ERR << "Incompatible libproxy detected (could not resolve px_proxy_factory_new): " << dlerror() << std::endl;
69 return nullptr;
70 }
71 apiInstance->deleteProxyFactory = (DelFactoryCb)::dlsym ( apiInstance->libProxyLibHandle, "px_proxy_factory_free" );
72 if ( !apiInstance->deleteProxyFactory ){
73 ERR << "Incompatible libproxy detected (could not resolve px_proxy_factory_free): " << dlerror() << std::endl;
74 return nullptr;
75 }
76 apiInstance->getProxies = (GetProxiesCb)::dlsym ( apiInstance->libProxyLibHandle, "px_proxy_factory_get_proxies" );
77 if ( !apiInstance->getProxies ){
78 ERR << "Incompatible libproxy detected (could not resolve px_proxy_factory_get_proxies): " << dlerror() << std::endl;
79 return nullptr;
80 }
81 apiInstance->freeProxies = (FreeProxiesCb)::dlsym ( apiInstance->libProxyLibHandle, "px_proxy_factory_free_proxies" );
82 if ( !apiInstance->freeProxies ){
83 MIL << "Older version of libproxy detected, using fallback function to free the proxy list (could not resolve px_proxy_factory_free_proxies): " << dlerror() << std::endl;
84 apiInstance->freeProxies = &fallbackFreeProxies;
85 }
86
87 MIL << "Libproxy is available" << std::endl;
88 return apiInstance;
89 }
90 };
91
92 LibProxyAPI *proxyApi() {
93 static std::unique_ptr<LibProxyAPI> api = LibProxyAPI::create();
94 return api.get();
95 }
96
97 LibProxyAPI &assertProxyApi() {
98 auto api = proxyApi();
99 if ( !api )
100 ZYPP_THROW( zypp::Exception("LibProxyAPI is not available.") );
101 return *api;
102 }
103 }
104
106 {
107 TmpUnsetEnv(const char *var_r) : _set(false), _var(var_r) {
108 const char * val = getenv( _var.c_str() );
109 if ( val )
110 {
111 _set = true;
112 _val = val;
113 ::unsetenv( _var.c_str() );
114 }
115 }
116
117 TmpUnsetEnv(const TmpUnsetEnv &) = delete;
121
123 {
124 if ( _set )
125 {
126 setenv( _var.c_str(), _val.c_str(), 1 );
127 }
128 }
129
130 bool _set;
131 std::string _var;
132 std::string _val;
133 };
134
136 {
137 static pxProxyFactoryType * proxyFactory = 0;
138
139 // Force libproxy into using "/etc/sysconfig/proxy"
140 // if it exists.
141 static WatchFile sysconfigProxy( "/etc/sysconfig/proxy", WatchFile::NO_INIT );
142 if ( sysconfigProxy.hasChanged() )
143 {
144 MIL << "Build Libproxy Factory from /etc/sysconfig/proxy" << endl;
145 if ( proxyFactory )
146 assertProxyApi().deleteProxyFactory( proxyFactory );
147
148 TmpUnsetEnv envguard[] __attribute__ ((__unused__)) = { "KDE_FULL_SESSION", "GNOME_DESKTOP_SESSION_ID", "DESKTOP_SESSION" };
149 proxyFactory = assertProxyApi().createProxyFactory();
150 }
151 else if ( ! proxyFactory )
152 {
153 MIL << "Build Libproxy Factory" << endl;
154 proxyFactory = assertProxyApi().createProxyFactory();
155 }
156
157 return proxyFactory;
158 }
159
161 : ProxyInfo::Impl()
162 , _factory( getProxyFactory())
163 {
164 _enabled = !(_factory == NULL);
165 }
166
169
171 {
172 return ( proxyApi () != nullptr );
173 }
174
175 std::string ProxyInfoLibproxy::proxy(const Url & url_r) const
176 {
177 if (!_enabled)
178 return "";
179
180 const url::ViewOption vopt =
181 url::ViewOption::WITH_SCHEME
182 + url::ViewOption::WITH_HOST
183 + url::ViewOption::WITH_PORT
184 + url::ViewOption::WITH_PATH_NAME;
185
186 auto &api = assertProxyApi ();
187
189 api.getProxies(_factory, (char *)url_r.asString(vopt).c_str())
190 , api.freeProxies
191 );
192 if ( !proxies.value() )
193 return "";
194
195 /* cURL can only handle HTTP proxies, not SOCKS. And can only handle
196 one. So look through the list and find an appropriate one. */
197 std::optional<std::string> result;
198 for (int i = 0; proxies[i]; i++) {
199 if ( !result && !strncmp(proxies[i], "http://", 7) ) {
200 result = str::asString( proxies[i] );
201 }
202 }
203
204 return result.value_or( "" );
205 }
206
209
212
213 } // namespace media
214} // namespace zypp
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition AutoDispose.h:95
reference value() const
Reference to the Tp object.
Base class for Exception.
Definition Exception.h:147
Url manipulation class.
Definition Url.h:92
std::string asString() const
Returns a default string representation of the Url object.
Definition Url.cc:501
Remember a files attributes to detect content changes.
Definition watchfile.h:50
bool hasChanged()
Definition watchfile.h:80
DefaultIntegral< bool, false > _enabled
ProxyInfo::NoProxyIterator noProxyBegin() const override
std::string proxy(const Url &url_r) const override
ProxyInfo::NoProxyIterator noProxyEnd() const override
ProxyInfo::NoProxyList _no_proxy
std::list< std::string >::const_iterator NoProxyIterator
Definition proxyinfo.h:35
char **(*)(ProxyFactoryType *self, const char *url) GetProxiesSig
void(*)(ProxyFactoryType *self) DelFactorySig
void(*)(char **proxies) FreeProxiesCb
ProxyFactoryType *(*)(void) CreateFactorySig
static pxProxyFactoryType * getProxyFactory()
const std::string & asString(const std::string &t)
Global asString() that works with std::string too.
Definition String.h:139
Easy-to use interface to the ZYPP dependency resolver.
DelFactoryCb deleteProxyFactory
FreeProxiesCb freeProxies
GetProxiesCb getProxies
zypp::AutoDispose< void * > libProxyLibHandle
CreateFactoryCb createProxyFactory
struct _pxProxyFactory pxProxyFactoryType
TmpUnsetEnv(TmpUnsetEnv &&)=delete
TmpUnsetEnv(const char *var_r)
TmpUnsetEnv & operator=(const TmpUnsetEnv &)=delete
TmpUnsetEnv & operator=(TmpUnsetEnv &&)=delete
TmpUnsetEnv(const TmpUnsetEnv &)=delete
Url::asString() view options.
Definition UrlBase.h:40
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:429
#define MIL
Definition Logger.h:98
#define ERR
Definition Logger.h:100