libzypp  17.37.10
proxyinfolibproxy.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
13 #include <zypp-core/AutoDispose.h>
14 #include <iostream>
15 #include <optional>
16 #include <cstdlib>
17 
18 #include <zypp-core/base/Logger.h>
19 #include <zypp-core/base/String.h>
20 #include <zypp-core/fs/WatchFile>
21 #include <zypp-core/Pathname.h>
22 
23 #include <zypp-curl/proxyinfo/ProxyInfoLibproxy>
24 
25 #include <dlfcn.h> // for dlload, dlsym, dlclose
26 #include <glib.h> // g_clear_pointer and g_strfreev
27 
28 using std::endl;
29 using namespace zypp::base;
30 
31 namespace zypp {
32  namespace env {
33  inline bool inYAST()
34  {
35  static const bool _inYAST { ::getenv("YAST_IS_RUNNING") };
36  return _inYAST;
37  }
38  }
39 
40  namespace media {
41 
42  namespace {
43 
44  using CreateFactoryCb = CreateFactorySig<pxProxyFactoryType>;
45  using DelFactoryCb = DelFactorySig<pxProxyFactoryType>;
46  using GetProxiesCb = GetProxiesSig<pxProxyFactoryType>;
47 
48  struct LibProxyAPI
49  {
51  CreateFactoryCb createProxyFactory = nullptr;
52  DelFactoryCb deleteProxyFactory = nullptr;
53  GetProxiesCb getProxies = nullptr;
55 
61  static void fallbackFreeProxies( char **proxies ) {
62  g_clear_pointer (&proxies, g_strfreev);
63  }
64 
65  static std::unique_ptr<LibProxyAPI> create() {
66  MIL << "Detecting libproxy availability" << std::endl;
67  zypp::AutoDispose<void *> handle( dlopen("libproxy.so.1", RTLD_LAZY ), []( void *ptr ){ if ( ptr ) ::dlclose(ptr); });
68  if ( !handle ) {
69  MIL << "No libproxy support detected (could not load library): " << dlerror() << std::endl;
70  return nullptr;
71  }
72 
73  std::unique_ptr<LibProxyAPI> apiInstance = std::make_unique<LibProxyAPI>();
74  apiInstance->libProxyLibHandle = std::move(handle);
75  apiInstance->createProxyFactory = (CreateFactoryCb)::dlsym ( apiInstance->libProxyLibHandle, "px_proxy_factory_new" );
76  if ( !apiInstance->createProxyFactory ){
77  ERR << "Incompatible libproxy detected (could not resolve px_proxy_factory_new): " << dlerror() << std::endl;
78  return nullptr;
79  }
80  apiInstance->deleteProxyFactory = (DelFactoryCb)::dlsym ( apiInstance->libProxyLibHandle, "px_proxy_factory_free" );
81  if ( !apiInstance->deleteProxyFactory ){
82  ERR << "Incompatible libproxy detected (could not resolve px_proxy_factory_free): " << dlerror() << std::endl;
83  return nullptr;
84  }
85  apiInstance->getProxies = (GetProxiesCb)::dlsym ( apiInstance->libProxyLibHandle, "px_proxy_factory_get_proxies" );
86  if ( !apiInstance->getProxies ){
87  ERR << "Incompatible libproxy detected (could not resolve px_proxy_factory_get_proxies): " << dlerror() << std::endl;
88  return nullptr;
89  }
90  apiInstance->freeProxies = (FreeProxiesCb)::dlsym ( apiInstance->libProxyLibHandle, "px_proxy_factory_free_proxies" );
91  if ( !apiInstance->freeProxies ){
92  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;
93  apiInstance->freeProxies = &fallbackFreeProxies;
94  }
95 
96  MIL << "Libproxy is available" << std::endl;
97  return apiInstance;
98  }
99  };
100 
101  LibProxyAPI *proxyApi() {
102  static std::unique_ptr<LibProxyAPI> api = LibProxyAPI::create();
103  return api.get();
104  }
105 
106  LibProxyAPI &assertProxyApi() {
107  auto api = proxyApi();
108  if ( !api )
109  ZYPP_THROW( zypp::Exception("LibProxyAPI is not available.") );
110  return *api;
111  }
112  }
113 
114  struct TmpUnsetEnv
115  {
116  TmpUnsetEnv(const char *var_r) : _set(false), _var(var_r) {
117  const char * val = getenv( _var.c_str() );
118  if ( val )
119  {
120  _set = true;
121  _val = val;
122  ::unsetenv( _var.c_str() );
123  }
124  }
125 
126  TmpUnsetEnv(const TmpUnsetEnv &) = delete;
127  TmpUnsetEnv(TmpUnsetEnv &&) = delete;
128  TmpUnsetEnv &operator=(const TmpUnsetEnv &) = delete;
129  TmpUnsetEnv &operator=(TmpUnsetEnv &&) = delete;
130 
132  {
133  if ( _set )
134  {
135  setenv( _var.c_str(), _val.c_str(), 1 );
136  }
137  }
138 
139  bool _set;
140  std::string _var;
141  std::string _val;
142  };
143 
145  {
146  static pxProxyFactoryType * proxyFactory = 0;
147 
148  // Force libproxy into using "/etc/sysconfig/proxy"
149  // if it exists.
150  static WatchFile sysconfigProxy( "/etc/sysconfig/proxy", WatchFile::NO_INIT );
151  if ( sysconfigProxy.hasChanged() )
152  {
153  MIL << "Build Libproxy Factory from /etc/sysconfig/proxy" << endl;
154  if ( proxyFactory )
155  assertProxyApi().deleteProxyFactory( proxyFactory );
156 
157  TmpUnsetEnv envguard[] __attribute__ ((__unused__)) = { "KDE_FULL_SESSION", "GNOME_DESKTOP_SESSION_ID", "DESKTOP_SESSION" };
158  proxyFactory = assertProxyApi().createProxyFactory();
159  }
160  else if ( ! proxyFactory )
161  {
162  MIL << "Build Libproxy Factory" << endl;
163  proxyFactory = assertProxyApi().createProxyFactory();
164  }
165 
166  return proxyFactory;
167  }
168 
169  ProxyInfoLibproxy::ProxyInfoLibproxy()
170  : ProxyInfo::Impl()
171  , _factory( getProxyFactory())
172  {
173  _enabled = !(_factory == NULL);
174  }
175 
177  {}
178 
180  {
181  return ( proxyApi () != nullptr );
182  }
183 
184  std::string ProxyInfoLibproxy::proxy(const Url & url_r) const
185  {
186  if (!_enabled)
187  return "";
188 
189  const url::ViewOption vopt =
190  url::ViewOption::WITH_SCHEME
191  + url::ViewOption::WITH_HOST
192  + url::ViewOption::WITH_PORT
193  + url::ViewOption::WITH_PATH_NAME;
194 
195  auto &api = assertProxyApi ();
196 
198  api.getProxies(_factory, url_r.asString(vopt).c_str())
199  , api.freeProxies
200  );
201  if ( !proxies.value() )
202  return "";
203 
204  // bsc#1244710: libproxy appears to return /etc/sysconfig/proxy
205  // values after $*_proxy environment variables.
206  // In YAST, e.g after changing the proxy settings, we'd like
207  // /etc/sysconfig/proxy changes to take effect immediately.
208  // So we pick the last one matching our schema.
209  const std::string myschema { url_r.getScheme()+":" };
210  std::optional<std::string> result;
211  for ( int i = 0; proxies[i]; ++i ) {
212  if ( str::hasPrefix( proxies[i], myschema ) ) {
213  result = str::asString( proxies[i] );
214  if ( not env::inYAST() )
215  break;
216  }
217  }
218 
219  return result.value_or( "" );
220  }
221 
223  { return _no_proxy.begin(); }
224 
226  { return _no_proxy.end(); }
227 
228  } // namespace media
229 } // namespace zypp
std::string getScheme() const
Returns the scheme name of the URL.
Definition: Url.cc:551
#define MIL
Definition: Logger.h:100
std::string proxy(const Url &url_r) const override
Namespace intended to collect all environment variables we use.
Definition: Env.h:24
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:459
bool hasChanged()
Definition: watchfile.h:80
FreeProxiesCb freeProxies
std::list< std::string >::const_iterator NoProxyIterator
Definition: proxyinfo.h:35
GetProxiesCb getProxies
const std::string & asString(const std::string &t)
Global asString() that works with std::string too.
Definition: String.h:140
Url::asString() view options.
Definition: UrlBase.h:40
#define ERR
Definition: Logger.h:102
Remember a files attributes to detect content changes.
Definition: watchfile.h:49
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:515
zypp::AutoDispose< void * > libProxyLibHandle
DefaultIntegral< bool, false > _enabled
static pxProxyFactoryType * getProxyFactory()
DelFactoryCb deleteProxyFactory
ProxyInfo::NoProxyList _no_proxy
ProxyInfo::NoProxyIterator noProxyEnd() const override
struct _pxProxyFactory pxProxyFactoryType
TmpUnsetEnv(const char *var_r)
struct zypp::media::MediaBlock __attribute__
Base class for Exception.
Definition: Exception.h:152
reference value() const
Reference to the Tp object.
Definition: AutoDispose.h:138
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:94
ProxyInfo::NoProxyIterator noProxyBegin() const override
CreateFactoryCb createProxyFactory
void(*)(char **proxies) FreeProxiesCb
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
Definition: String.h:1098
Url manipulation class.
Definition: Url.h:92