Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qnetworkproxy_libproxy.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2017 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qnetworkproxy.h"
6
7#ifndef QT_NO_NETWORKPROXY
8
9#include <QtCore/QByteArray>
10#include <QtCore/QMutex>
11#include <QtCore/QSemaphore>
12#include <QtCore/QUrl>
13#include <QtCore/private/qeventdispatcher_unix_p.h>
14#include <QtCore/private/qthread_p.h>
15#include <QtCore/qapplicationstatic.h>
16
17#include <proxy.h>
18#include <dlfcn.h>
19
21
22using namespace Qt::StringLiterals;
23
24static bool isThreadingNeeded()
25{
26 // Try to guess if the libproxy we linked to is from the libproxy project
27 // or if it is from pacrunner. Neither library is thread-safe, but the one
28 // from libproxy is worse, since it may launch JS engines that don't take
29 // kindly to being executed from multiple threads (even if at different
30 // times). The pacrunner implementation doesn't suffer from this because
31 // the JS execution is out of process, in the pacrunner daemon.
32
33 void *sym;
34
35#ifdef Q_CC_GNU
36 // Search for the mangled name of the virtual table of the pacrunner
37 // extension. Even if libproxy begins using -fvisibility=hidden, this
38 // symbol can't be hidden.
39 sym = dlsym(RTLD_DEFAULT, "_ZTVN8libproxy19pacrunner_extensionE");
40#else
41 // The default libproxy one uses libmodman for its module management and
42 // leaks symbols because it doesn't use -fvisibility=hidden (as of
43 // v0.4.15).
44 sym = dlsym(RTLD_DEFAULT, "mm_info_ignore_hostname");
45#endif
46
47 return sym != nullptr;
48}
49
50class QLibProxyWrapper : public QDaemonThread
51{
53public:
56
57 QList<QUrl> getProxies(const QUrl &url);
58
59private:
60 struct Data {
61 // we leave the conversion to/from QUrl to the calling thread
62 const char *url;
63 char **proxies;
64 QSemaphore replyReady;
65 };
66
67 void run() override;
68
69 pxProxyFactory *factory; // not subject to the mutex
70
71 QMutex mutex;
72 QSemaphore requestReady;
73 Data *request;
74};
75
77
79{
80 if (isThreadingNeeded()) {
81 setEventDispatcher(new QEventDispatcherUNIX); // don't allow the Glib one
82 start();
83 } else {
84 factory = px_proxy_factory_new();
86 }
87}
88
90{
91 if (isRunning()) {
92 requestInterruption();
93 requestReady.release();
94 wait();
95 } else {
96 px_proxy_factory_free(factory);
97 }
98}
99
100/*
101 Gets the list of proxies from libproxy, converted to QUrl list. Apply
102 thread-safety, though its documentation says otherwise, libproxy isn't
103 thread-safe.
104*/
106{
107 QByteArray encodedUrl = url.toEncoded();
108 Data data;
109 data.url = encodedUrl.constData();
110
111 {
112 QMutexLocker locker(&mutex);
113 if (isRunning()) {
114 // threaded mode
115 // it's safe to write to request because we hold the mutex:
116 // our aux thread is blocked waiting for work and no other thread
117 // could have got here
118 request = &data;
119 requestReady.release();
120
121 // wait for the reply
122 data.replyReady.acquire();
123 } else {
124 // non-threaded mode
125 data.proxies = px_proxy_factory_get_proxies(factory, data.url);
126 }
127 }
128
129 QList<QUrl> ret;
130 if (data.proxies) {
131 for (int i = 0; data.proxies[i]; i++) {
132 ret.append(QUrl::fromEncoded(data.proxies[i]));
133 free(data.proxies[i]);
134 }
135 free(data.proxies);
136 }
137 return ret;
138}
139
141{
142 factory = px_proxy_factory_new();
143 Q_CHECK_PTR(factory);
144
145 forever {
146 requestReady.acquire();
147 if (isInterruptionRequested())
148 break;
149 request->proxies = px_proxy_factory_get_proxies(factory, request->url);
150 request->replyReady.release();
151 }
152
153 px_proxy_factory_free(factory);
154}
155
157{
158 QList<QNetworkProxy> proxyList;
159
160 QUrl queryUrl;
161 QNetworkProxy::Capabilities requiredCapabilities(0);
162 switch (query.queryType()) {
163 //URL requests are directly supported by libproxy
165 queryUrl = query.url();
166 break;
167 // fake URLs to get libproxy to tell us the SOCKS proxy
169 if (queryUrl.scheme().isEmpty())
170 queryUrl.setScheme(QStringLiteral("tcp"));
171 queryUrl.setHost(query.peerHostName());
172 queryUrl.setPort(query.peerPort());
173 requiredCapabilities |= QNetworkProxy::TunnelingCapability;
174 break;
176 if (queryUrl.scheme().isEmpty())
177 queryUrl.setScheme(QStringLiteral("udp"));
178 queryUrl.setHost(query.peerHostName());
179 queryUrl.setPort(query.peerPort());
180 requiredCapabilities |= QNetworkProxy::UdpTunnelingCapability;
181 break;
182 default:
183 proxyList.append(QNetworkProxy(QNetworkProxy::NoProxy));
184 return proxyList;
185 }
186
187 const QList<QUrl> rawProxies = libProxyWrapper()->getProxies(queryUrl);
188
189 bool haveDirectConnection = false;
190 for (const QUrl& url : rawProxies) {
192 const QString scheme = url.scheme();
193 if (scheme == "http"_L1) {
195 } else if (scheme == "socks"_L1 || scheme == "socks5"_L1) {
197 } else if (scheme == "ftp"_L1) {
199 } else if (scheme == "direct"_L1) {
201 haveDirectConnection = true;
202 } else {
203 continue; //unsupported proxy type e.g. socks4
204 }
205
208 url.port(0),
211
212 if ((proxy.capabilities() & requiredCapabilities) == requiredCapabilities)
213 proxyList.append(proxy);
214 }
215
216 // fallback is direct connection
217 if (proxyList.isEmpty() || !haveDirectConnection)
218 proxyList.append(QNetworkProxy(QNetworkProxy::NoProxy));
219
220 return proxyList;
221}
222
224
225#include "qnetworkproxy_libproxy.moc"
226
227#endif
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
QList< QUrl > getProxies(const QUrl &url)
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qmutex.h:281
static QList< QNetworkProxy > systemProxyForQuery(const QNetworkProxyQuery &query=QNetworkProxyQuery())
This function takes the query request, query, examines the details of the type of socket or request a...
The QNetworkProxyQuery class is used to query the proxy settings for a socket.
The QNetworkProxy class provides a network layer proxy.
ProxyType
This enum describes the types of network proxying provided in Qt.
Capabilities capabilities() const
\inmodule QtCore
Definition qsemaphore.h:18
void acquire(int n=1)
Tries to acquire n resources guarded by the semaphore.
void release(int n=1)
Releases n resources guarded by the semaphore.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
\inmodule QtCore
Definition qurl.h:94
QString userName(ComponentFormattingOptions options=FullyDecoded) const
Returns the user name of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2199
QString host(ComponentFormattingOptions=FullyDecoded) const
Returns the host of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2340
QByteArray toEncoded(FormattingOptions options=FullyEncoded) const
Returns the encoded representation of the URL if it's valid; otherwise an empty QByteArray is returne...
Definition qurl.cpp:2967
QString password(ComponentFormattingOptions=FullyDecoded) const
Returns the password of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2262
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1991
int port(int defaultPort=-1) const
Definition qurl.cpp:2383
@ FullyDecoded
Definition qurl.h:130
@ EncodeUnicode
Definition qurl.h:123
static QUrl fromEncoded(QByteArrayView input, ParsingMode mode=TolerantMode)
Parses input and returns the corresponding QUrl.
Definition qurl.cpp:2988
Combined button and popup list for selecting options.
#define Q_APPLICATION_STATIC(TYPE, NAME,...)
#define forever
Definition qforeach.h:78
return ret
static bool isThreadingNeeded()
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLuint start
GLenum query
#define QStringLiteral(str)
static bool isRunning()
Definition main.cpp:452
#define Q_OBJECT
Q_CHECK_PTR(a=new int[80])
QUrl url("example.com")
[constructor-url-reference]
QItemEditorFactory * factory
QNetworkProxy proxy
[0]