Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2017 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtNetwork module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qnetworkproxy.h"
42
43#ifndef QT_NO_NETWORKPROXY
44
45#include <QtCore/QByteArray>
46#include <QtCore/QMutex>
47#include <QtCore/QSemaphore>
48#include <QtCore/QUrl>
49#include <QtCore/private/qeventdispatcher_unix_p.h>
50#include <QtCore/private/qthread_p.h>
51
52#include <proxy.h>
53#include <dlfcn.h>
54
55QT_BEGIN_NAMESPACE
56
57static bool isThreadingNeeded()
58{
59 // Try to guess if the libproxy we linked to is from the libproxy project
60 // or if it is from pacrunner. Neither library is thread-safe, but the one
61 // from libproxy is worse, since it may launch JS engines that don't take
62 // kindly to being executed from multiple threads (even if at different
63 // times). The pacrunner implementation doesn't suffer from this because
64 // the JS execution is out of process, in the pacrunner daemon.
65
66 void *sym;
67
68#ifdef Q_CC_GNU
69 // Search for the mangled name of the virtual table of the pacrunner
70 // extension. Even if libproxy begins using -fvisibility=hidden, this
71 // symbol can't be hidden.
72 sym = dlsym(RTLD_DEFAULT, "_ZTVN8libproxy19pacrunner_extensionE");
73#else
74 // The default libproxy one uses libmodman for its module management and
75 // leaks symbols because it doesn't use -fvisibility=hidden (as of
76 // v0.4.15).
77 sym = dlsym(RTLD_DEFAULT, "mm_info_ignore_hostname");
78#endif
79
80 return sym != nullptr;
81}
82
83class QLibProxyWrapper : public QDaemonThread
84{
85 Q_OBJECT
86public:
87 QLibProxyWrapper();
88 ~QLibProxyWrapper();
89
90 QList<QUrl> getProxies(const QUrl &url);
91
92private:
93 struct Data {
94 // we leave the conversion to/from QUrl to the calling thread
95 const char *url;
96 char **proxies;
97 QSemaphore replyReady;
98 };
99
100 void run() override;
101
102 pxProxyFactory *factory; // not subject to the mutex
103
104 QMutex mutex;
105 QSemaphore requestReady;
106 Data *request;
107};
108
109Q_GLOBAL_STATIC(QLibProxyWrapper, libProxyWrapper);
110
111QLibProxyWrapper::QLibProxyWrapper()
112{
113 if (isThreadingNeeded()) {
114 setEventDispatcher(new QEventDispatcherUNIX); // don't allow the Glib one
115 start();
116 } else {
117 factory = px_proxy_factory_new();
118 Q_CHECK_PTR(factory);
119 }
120}
121
122QLibProxyWrapper::~QLibProxyWrapper()
123{
124 if (isRunning()) {
125 requestInterruption();
126 requestReady.release();
127 wait();
128 } else {
129 px_proxy_factory_free(factory);
130 }
131}
132
133/*
134 Gets the list of proxies from libproxy, converted to QUrl list. Apply
135 thread-safety, though its documentation says otherwise, libproxy isn't
136 thread-safe.
137*/
138QList<QUrl> QLibProxyWrapper::getProxies(const QUrl &url)
139{
140 QByteArray encodedUrl = url.toEncoded();
141 Data data;
142 data.url = encodedUrl.constData();
143
144 {
145 QMutexLocker locker(&mutex);
146 if (isRunning()) {
147 // threaded mode
148 // it's safe to write to request because we hold the mutex:
149 // our aux thread is blocked waiting for work and no other thread
150 // could have got here
151 request = &data;
152 requestReady.release();
153
154 // wait for the reply
155 data.replyReady.acquire();
156 } else {
157 // non-threaded mode
158 data.proxies = px_proxy_factory_get_proxies(factory, data.url);
159 }
160 }
161
162 QList<QUrl> ret;
163 if (data.proxies) {
164 for (int i = 0; data.proxies[i]; i++) {
165 ret.append(QUrl::fromEncoded(data.proxies[i]));
166 free(data.proxies[i]);
167 }
168 free(data.proxies);
169 }
170 return ret;
171}
172
173void QLibProxyWrapper::run()
174{
175 factory = px_proxy_factory_new();
176 Q_CHECK_PTR(factory);
177
178 forever {
179 requestReady.acquire();
180 if (isInterruptionRequested())
181 break;
182 request->proxies = px_proxy_factory_get_proxies(factory, request->url);
183 request->replyReady.release();
184 }
185
186 px_proxy_factory_free(factory);
187}
188
189QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &query)
190{
191 QList<QNetworkProxy> proxyList;
192
193 QUrl queryUrl;
194 QNetworkProxy::Capabilities requiredCapabilities(0);
195 switch (query.queryType()) {
196 //URL requests are directly supported by libproxy
197 case QNetworkProxyQuery::UrlRequest:
198 queryUrl = query.url();
199 break;
200 // fake URLs to get libproxy to tell us the SOCKS proxy
201 case QNetworkProxyQuery::TcpSocket:
202 queryUrl.setScheme(QStringLiteral("tcp"));
203 queryUrl.setHost(query.peerHostName());
204 queryUrl.setPort(query.peerPort());
205 requiredCapabilities |= QNetworkProxy::TunnelingCapability;
206 break;
207 case QNetworkProxyQuery::UdpSocket:
208 queryUrl.setScheme(QStringLiteral("udp"));
209 queryUrl.setHost(query.peerHostName());
210 queryUrl.setPort(query.peerPort());
211 requiredCapabilities |= QNetworkProxy::UdpTunnelingCapability;
212 break;
213 default:
214 proxyList.append(QNetworkProxy(QNetworkProxy::NoProxy));
215 return proxyList;
216 }
217
218 const QList<QUrl> rawProxies = libProxyWrapper()->getProxies(queryUrl);
219
220 bool haveDirectConnection = false;
221 for (const QUrl& url : rawProxies) {
222 QNetworkProxy::ProxyType type;
223 const QString scheme = url.scheme();
224 if (scheme == QLatin1String("http")) {
225 type = QNetworkProxy::HttpProxy;
226 } else if (scheme == QLatin1String("socks")
227 || scheme == QLatin1String("socks5")) {
228 type = QNetworkProxy::Socks5Proxy;
229 } else if (scheme == QLatin1String("ftp")) {
230 type = QNetworkProxy::FtpCachingProxy;
231 } else if (scheme == QLatin1String("direct")) {
232 type = QNetworkProxy::NoProxy;
233 haveDirectConnection = true;
234 } else {
235 continue; //unsupported proxy type e.g. socks4
236 }
237
238 QNetworkProxy proxy(type,
239 url.host(QUrl::EncodeUnicode),
240 url.port(0),
241 url.userName(QUrl::FullyDecoded),
242 url.password(QUrl::FullyDecoded));
243
244 if ((proxy.capabilities() & requiredCapabilities) == requiredCapabilities)
245 proxyList.append(proxy);
246 }
247
248 // fallback is direct connection
249 if (proxyList.isEmpty() || !haveDirectConnection)
250 proxyList.append(QNetworkProxy(QNetworkProxy::NoProxy));
251
252 return proxyList;
253}
254
255QT_END_NAMESPACE
256
257#include "qnetworkproxy_libproxy.moc"
258
259#endif
260

Warning: That file was not part of the compilation database. It may have many parsing errors.