libzypp  17.37.5
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 
17 #include <zypp-core/base/Logger.h>
18 #include <zypp-core/base/String.h>
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 
27 using std::endl;
28 using namespace zypp::base;
29 
30 namespace 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 
105  struct TmpUnsetEnv
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;
118  TmpUnsetEnv(TmpUnsetEnv &&) = delete;
119  TmpUnsetEnv &operator=(const TmpUnsetEnv &) = delete;
120  TmpUnsetEnv &operator=(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 
160  ProxyInfoLibproxy::ProxyInfoLibproxy()
161  : ProxyInfo::Impl()
162  , _factory( getProxyFactory())
163  {
164  _enabled = !(_factory == NULL);
165  }
166 
168  {}
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, 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 
208  { return _no_proxy.begin(); }
209 
211  { return _no_proxy.end(); }
212 
213  } // namespace media
214 } // namespace zypp
#define MIL
Definition: Logger.h:100
std::string proxy(const Url &url_r) const override
#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
Url manipulation class.
Definition: Url.h:92