Qt 6.x
The Qt SDK
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
16#include <proxy.h>
17#include <dlfcn.h>
18
20
21using namespace Qt::StringLiterals;
22
23static bool isThreadingNeeded()
24{
25 // Try to guess if the libproxy we linked to is from the libproxy project
26 // or if it is from pacrunner. Neither library is thread-safe, but the one
27 // from libproxy is worse, since it may launch JS engines that don't take
28 // kindly to being executed from multiple threads (even if at different
29 // times). The pacrunner implementation doesn't suffer from this because
30 // the JS execution is out of process, in the pacrunner daemon.
31
32 void *sym;
33
34#ifdef Q_CC_GNU
35 // Search for the mangled name of the virtual table of the pacrunner
36 // extension. Even if libproxy begins using -fvisibility=hidden, this
37 // symbol can't be hidden.
38 sym = dlsym(RTLD_DEFAULT, "_ZTVN8libproxy19pacrunner_extensionE");
39#else
40 // The default libproxy one uses libmodman for its module management and
41 // leaks symbols because it doesn't use -fvisibility=hidden (as of
42 // v0.4.15).
43 sym = dlsym(RTLD_DEFAULT, "mm_info_ignore_hostname");
44#endif
45
46 return sym != nullptr;
47}
48
49class QLibProxyWrapper : public QDaemonThread
50{
52public:
55
57
58private:
59 struct Data {
60 // we leave the conversion to/from QUrl to the calling thread
61 const char *url;
62 char **proxies;
63 QSemaphore replyReady;
64 };
65
66 void run() override;
67
68 pxProxyFactory *factory; // not subject to the mutex
69
70 QMutex mutex;
71 QSemaphore requestReady;
72 Data *request;
73};
74
76
78{
79 if (isThreadingNeeded()) {
80 setEventDispatcher(new QEventDispatcherUNIX); // don't allow the Glib one
81 start();
82 } else {
83 factory = px_proxy_factory_new();
84 Q_CHECK_PTR(factory);
85 }
86}
87
89{
90 if (isRunning()) {
91 requestInterruption();
92 requestReady.release();
93 wait();
94 } else {
95 px_proxy_factory_free(factory);
96 }
97}
98
99/*
100 Gets the list of proxies from libproxy, converted to QUrl list. Apply
101 thread-safety, though its documentation says otherwise, libproxy isn't
102 thread-safe.
103*/
105{
106 QByteArray encodedUrl = url.toEncoded();
107 Data data;
108 data.url = encodedUrl.constData();
109
110 {
111 QMutexLocker locker(&mutex);
112 if (isRunning()) {
113 // threaded mode
114 // it's safe to write to request because we hold the mutex:
115 // our aux thread is blocked waiting for work and no other thread
116 // could have got here
117 request = &data;
118 requestReady.release();
119
120 // wait for the reply
121 data.replyReady.acquire();
122 } else {
123 // non-threaded mode
124 data.proxies = px_proxy_factory_get_proxies(factory, data.url);
125 }
126 }
127
129 if (data.proxies) {
130 for (int i = 0; data.proxies[i]; i++) {
131 ret.append(QUrl::fromEncoded(data.proxies[i]));
132 free(data.proxies[i]);
133 }
134 free(data.proxies);
135 }
136 return ret;
137}
138
140{
141 factory = px_proxy_factory_new();
142 Q_CHECK_PTR(factory);
143
144 forever {
145 requestReady.acquire();
146 if (isInterruptionRequested())
147 break;
148 request->proxies = px_proxy_factory_get_proxies(factory, request->url);
149 request->replyReady.release();
150 }
151
152 px_proxy_factory_free(factory);
153}
154
156{
157 QList<QNetworkProxy> proxyList;
158
159 QUrl queryUrl;
160 QNetworkProxy::Capabilities requiredCapabilities(0);
161 switch (query.queryType()) {
162 //URL requests are directly supported by libproxy
164 queryUrl = query.url();
165 break;
166 // fake URLs to get libproxy to tell us the SOCKS proxy
168 queryUrl.setScheme(QStringLiteral("tcp"));
169 queryUrl.setHost(query.peerHostName());
170 queryUrl.setPort(query.peerPort());
171 requiredCapabilities |= QNetworkProxy::TunnelingCapability;
172 break;
174 queryUrl.setScheme(QStringLiteral("udp"));
175 queryUrl.setHost(query.peerHostName());
176 queryUrl.setPort(query.peerPort());
177 requiredCapabilities |= QNetworkProxy::UdpTunnelingCapability;
178 break;
179 default:
181 return proxyList;
182 }
183
184 const QList<QUrl> rawProxies = libProxyWrapper()->getProxies(queryUrl);
185
186 bool haveDirectConnection = false;
187 for (const QUrl& url : rawProxies) {
189 const QString scheme = url.scheme();
190 if (scheme == "http"_L1) {
192 } else if (scheme == "socks"_L1 || scheme == "socks5"_L1) {
194 } else if (scheme == "ftp"_L1) {
196 } else if (scheme == "direct"_L1) {
198 haveDirectConnection = true;
199 } else {
200 continue; //unsupported proxy type e.g. socks4
201 }
202
205 url.port(0),
208
209 if ((proxy.capabilities() & requiredCapabilities) == requiredCapabilities)
210 proxyList.append(proxy);
211 }
212
213 // fallback is direct connection
214 if (proxyList.isEmpty() || !haveDirectConnection)
216
217 return proxyList;
218}
219
221
222#include "qnetworkproxy_libproxy.moc"
223
224#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:122
QList< QUrl > getProxies(const QUrl &url)
Definition qlist.h:74
bool isEmpty() const noexcept
Definition qlist.h:390
void append(parameter_type t)
Definition qlist.h:441
\inmodule QtCore
Definition qmutex.h:317
\inmodule QtCore
Definition qmutex.h:285
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:16
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:127
\inmodule QtCore
Definition qurl.h:94
QString url(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2814
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:2196
QString host(ComponentFormattingOptions=FullyDecoded) const
Returns the host of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2337
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:2964
QString password(ComponentFormattingOptions=FullyDecoded) const
Returns the password of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2259
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1983
void setScheme(const QString &scheme)
Sets the scheme of the URL to scheme.
Definition qurl.cpp:1959
void setHost(const QString &host, ParsingMode mode=DecodedMode)
Sets the host of the URL to host.
Definition qurl.cpp:2286
int port(int defaultPort=-1) const
Definition qurl.cpp:2380
@ 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:2985
void setPort(int port)
Sets the port of the URL to port.
Definition qurl.cpp:2355
Combined button and popup list for selecting options.
#define forever
Definition qforeach.h:78
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
return ret
static bool isThreadingNeeded()
GLenum type
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLenum query
#define QStringLiteral(str)
static bool isRunning()
Definition main.cpp:358
#define Q_OBJECT
Q_CHECK_PTR(a=new int[80])
QUrl url("example.com")
[constructor-url-reference]
QNetworkProxy proxy
[0]