source: trunk/src/network/kernel/qnetworkproxy.cpp@ 352

Last change on this file since 352 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 39.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtNetwork module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42
43/*!
44 \class QNetworkProxy
45
46 \since 4.1
47
48 \brief The QNetworkProxy class provides a network layer proxy.
49
50 \reentrant
51 \ingroup io
52 \inmodule QtNetwork
53
54 QNetworkProxy provides the method for configuring network layer
55 proxy support to the Qt network classes. The currently supported
56 classes are QAbstractSocket, QTcpSocket, QUdpSocket, QTcpServer,
57 QHttp and QFtp. The proxy support is designed to be as transparent
58 as possible. This means that existing network-enabled applications
59 that you have written should automatically support network proxy
60 using the following code.
61
62 \snippet doc/src/snippets/code/src_network_kernel_qnetworkproxy.cpp 0
63
64 An alternative to setting an application wide proxy is to specify
65 the proxy for individual sockets using QAbstractSocket::setProxy()
66 and QTcpServer::setProxy(). In this way, it is possible to disable
67 the use of a proxy for specific sockets using the following code:
68
69 \snippet doc/src/snippets/code/src_network_kernel_qnetworkproxy.cpp 1
70
71 Network proxy is not used if the address used in \l
72 {QAbstractSocket::connectToHost()}{connectToHost()}, \l
73 {QUdpSocket::bind()}{bind()} or \l
74 {QTcpServer::listen()}{listen()} is equivalent to
75 QHostAddress::LocalHost or QHostAddress::LocalHostIPv6.
76
77 Each type of proxy support has certain restrictions associated with it.
78 You should read the \l{ProxyType} documentation carefully before
79 selecting a proxy type to use.
80
81 \note Changes made to currently connected sockets do not take effect.
82 If you need to change a connected socket, you should reconnect it.
83
84 \section1 SOCKS5
85
86 The SOCKS5 support in Qt 4 is based on \l{RFC 1928} and \l{RFC 1929}.
87 The supported authentication methods are no authentication and
88 username/password authentication. Both IPv4 and IPv6 are
89 supported, but domain name resolution via the SOCKS server is not
90 supported; i.e. all domain names are resolved locally. There are
91 several things to remember when using SOCKS5 with QUdpSocket and
92 QTcpServer:
93
94 With QUdpSocket, a call to \l {QUdpSocket::bind()}{bind()} may fail
95 with a timeout error. If a port number other than 0 is passed to
96 \l {QUdpSocket::bind()}{bind()}, it is not guaranteed that it is the
97 specified port that will be used.
98 Use \l{QUdpSocket::localPort()}{localPort()} and
99 \l{QUdpSocket::localAddress()}{localAddress()} to get the actual
100 address and port number in use. Because proxied UDP goes through
101 two UDP connections, it is more likely that packets will be dropped.
102
103 With QTcpServer a call to \l{QTcpServer::listen()}{listen()} may
104 fail with a timeout error. If a port number other than 0 is passed
105 to \l{QTcpServer::listen()}{listen()}, then it is not guaranteed
106 that it is the specified port that will be used.
107 Use \l{QTcpServer::serverPort()}{serverPort()} and
108 \l{QTcpServer::serverAddress()}{serverAddress()} to get the actual
109 address and port used to listen for connections. SOCKS5 only supports
110 one accepted connection per call to \l{QTcpServer::listen()}{listen()},
111 and each call is likely to result in a different
112 \l{QTcpServer::serverPort()}{serverPort()} being used.
113
114 \sa QAbstractSocket, QTcpServer
115*/
116
117/*!
118 \enum QNetworkProxy::ProxyType
119
120 This enum describes the types of network proxying provided in Qt.
121
122 There are two types of proxies that Qt understands:
123 transparent proxies and caching proxies. The first group consists
124 of proxies that can handle any arbitrary data transfer, while the
125 second can only handle specific requests. The caching proxies only
126 make sense for the specific classes where they can be used.
127
128 \value NoProxy No proxying is used
129 \value DefaultProxy Proxy is determined based on the application proxy set using setApplicationProxy()
130 \value Socks5Proxy \l Socks5 proxying is used
131 \value HttpProxy HTTP transparent proxying is used
132 \value HttpCachingProxy Proxying for HTTP requests only
133 \value FtpCachingProxy Proxying for FTP requests only
134
135 The table below lists different proxy types and their
136 capabilities. Since each proxy type has different capabilities, it
137 is important to understand them before choosing a proxy type.
138
139 \table
140 \header
141 \o Proxy type
142 \o Description
143 \o Default capabilities
144
145 \row
146 \o SOCKS 5
147 \o Generic proxy for any kind of connection. Supports TCP,
148 UDP, binding to a port (incoming connections) and
149 authentication.
150 \o TunnelingCapability, ListeningCapability,
151 UdpTunnelingCapability, HostNameLookupCapability
152
153 \row
154 \o HTTP
155 \o Implemented using the "CONNECT" command, supports only
156 outgoing TCP connections; supports authentication.
157 \o TunnelingCapability, CachingCapability, HostNameLookupCapability
158
159 \row
160 \o Caching-only HTTP
161 \o Implemented using normal HTTP commands, it is useful only
162 in the context of HTTP requests (see QHttp,
163 QNetworkAccessManager)
164 \o CachingCapability, HostNameLookupCapability
165
166 \row
167 \o Caching FTP
168 \o Implemented using an FTP proxy, it is useful only in the
169 context of FTP requests (see QFtp,
170 QNetworkAccessManager)
171 \o CachingCapability, HostNameLookupCapability
172
173 \endtable
174
175 Also note that you shouldn't set the application default proxy
176 (setApplicationProxy()) to a proxy that doesn't have the
177 TunnelingCapability capability. If you do, QTcpSocket will not
178 know how to open connections.
179
180 \sa setType(), type(), capabilities(), setCapabilities()
181*/
182
183/*!
184 \enum QNetworkProxy::Capability
185 \since 4.5
186
187 These flags indicate the capabilities that a given proxy server
188 supports.
189
190 QNetworkProxy sets different capabilities by default when the
191 object is created (see QNetworkProxy::ProxyType for a list of the
192 defaults). However, it is possible to change the capabitilies
193 after the object has been created with setCapabilities().
194
195 The capabilities that QNetworkProxy supports are:
196
197 \value TunnelingCapability Ability to open transparent, tunneled
198 TCP connections to a remote host. The proxy server relays the
199 transmission verbatim from one side to the other and does no
200 caching.
201
202 \value ListeningCapability Ability to create a listening socket
203 and wait for an incoming TCP connection from a remote host.
204
205 \value UdpTunnelingCapability Ability to relay UDP datagrams via
206 the proxy server to and from a remote host.
207
208 \value CachingCapability Ability to cache the contents of the
209 transfer. This capability is specific to each protocol and proxy
210 type. For example, HTTP proxies can cache the contents of web data
211 transferred with "GET" commands.
212
213 \value HostNameLookupCapability Ability to connect to perform the
214 lookup on a remote host name and connect to it, as opposed to
215 requiring the application to perform the name lookup and request
216 connection to IP addresses only.
217*/
218
219#include "qnetworkproxy.h"
220
221#ifndef QT_NO_NETWORKPROXY
222
223#include "private/qsocks5socketengine_p.h"
224#include "private/qhttpsocketengine_p.h"
225#include "qauthenticator.h"
226#include "qhash.h"
227#include "qmutex.h"
228#include "qurl.h"
229
230QT_BEGIN_NAMESPACE
231
232class QSocks5SocketEngineHandler;
233class QHttpSocketEngineHandler;
234
235class QGlobalNetworkProxy
236{
237public:
238 QGlobalNetworkProxy()
239 : mutex(QMutex::Recursive)
240 , applicationLevelProxy(0)
241 , applicationLevelProxyFactory(0)
242 , socks5SocketEngineHandler(0)
243 , httpSocketEngineHandler(0)
244 {
245 }
246
247 ~QGlobalNetworkProxy()
248 {
249 delete applicationLevelProxy;
250 delete applicationLevelProxyFactory;
251 delete socks5SocketEngineHandler;
252 delete httpSocketEngineHandler;
253 }
254
255 void init()
256 {
257 QMutexLocker lock(&mutex);
258#ifndef QT_NO_SOCKS5
259 if (!socks5SocketEngineHandler)
260 socks5SocketEngineHandler = new QSocks5SocketEngineHandler();
261#endif
262#ifndef QT_NO_HTTP
263 if (!httpSocketEngineHandler)
264 httpSocketEngineHandler = new QHttpSocketEngineHandler();
265#endif
266 }
267
268 void setApplicationProxy(const QNetworkProxy &proxy)
269 {
270 QMutexLocker lock(&mutex);
271 if (!applicationLevelProxy)
272 applicationLevelProxy = new QNetworkProxy;
273 *applicationLevelProxy = proxy;
274 delete applicationLevelProxyFactory;
275 applicationLevelProxyFactory = 0;
276 }
277
278 void setApplicationProxyFactory(QNetworkProxyFactory *factory)
279 {
280 QMutexLocker lock(&mutex);
281 if (applicationLevelProxy)
282 *applicationLevelProxy = QNetworkProxy();
283 delete applicationLevelProxyFactory;
284 applicationLevelProxyFactory = factory;
285 }
286
287 QNetworkProxy applicationProxy()
288 {
289 return proxyForQuery(QNetworkProxyQuery()).first();
290 }
291
292 QList<QNetworkProxy> proxyForQuery(const QNetworkProxyQuery &query);
293
294private:
295 QMutex mutex;
296 QNetworkProxy *applicationLevelProxy;
297 QNetworkProxyFactory *applicationLevelProxyFactory;
298 QSocks5SocketEngineHandler *socks5SocketEngineHandler;
299 QHttpSocketEngineHandler *httpSocketEngineHandler;
300};
301
302QList<QNetworkProxy> QGlobalNetworkProxy::proxyForQuery(const QNetworkProxyQuery &query)
303{
304 QMutexLocker locker(&mutex);
305
306 QList<QNetworkProxy> result;
307 if (!applicationLevelProxyFactory) {
308 if (applicationLevelProxy
309 && applicationLevelProxy->type() != QNetworkProxy::DefaultProxy)
310 result << *applicationLevelProxy;
311 else
312 result << QNetworkProxy(QNetworkProxy::NoProxy);
313 return result;
314 }
315
316 // we have a factory
317 result = applicationLevelProxyFactory->queryProxy(query);
318 if (result.isEmpty()) {
319 qWarning("QNetworkProxyFactory: factory %p has returned an empty result set",
320 applicationLevelProxyFactory);
321 result << QNetworkProxy(QNetworkProxy::NoProxy);
322 }
323 return result;
324}
325
326Q_GLOBAL_STATIC(QGlobalNetworkProxy, globalNetworkProxy);
327
328namespace {
329 template<bool> struct StaticAssertTest;
330 template<> struct StaticAssertTest<true> { enum { Value = 1 }; };
331}
332
333static inline void qt_noop_with_arg(int) {}
334#define q_static_assert(expr) qt_noop_with_arg(sizeof(StaticAssertTest< expr >::Value))
335
336static QNetworkProxy::Capabilities defaultCapabilitiesForType(QNetworkProxy::ProxyType type)
337{
338 q_static_assert(int(QNetworkProxy::DefaultProxy) == 0);
339 q_static_assert(int(QNetworkProxy::FtpCachingProxy) == 5);
340 static const int defaults[] =
341 {
342 /* [QNetworkProxy::DefaultProxy] = */
343 (int(QNetworkProxy::ListeningCapability) |
344 int(QNetworkProxy::TunnelingCapability) |
345 int(QNetworkProxy::UdpTunnelingCapability)),
346 /* [QNetworkProxy::Socks5Proxy] = */
347 (int(QNetworkProxy::TunnelingCapability) |
348 int(QNetworkProxy::ListeningCapability) |
349 int(QNetworkProxy::UdpTunnelingCapability) |
350 int(QNetworkProxy::HostNameLookupCapability)),
351 // it's weird to talk about the proxy capabilities of a "not proxy"...
352 /* [QNetworkProxy::NoProxy] = */
353 (int(QNetworkProxy::ListeningCapability) |
354 int(QNetworkProxy::TunnelingCapability) |
355 int(QNetworkProxy::UdpTunnelingCapability)),
356 /* [QNetworkProxy::HttpProxy] = */
357 (int(QNetworkProxy::TunnelingCapability) |
358 int(QNetworkProxy::CachingCapability) |
359 int(QNetworkProxy::HostNameLookupCapability)),
360 /* [QNetworkProxy::HttpCachingProxy] = */
361 (int(QNetworkProxy::CachingCapability) |
362 int(QNetworkProxy::HostNameLookupCapability)),
363 /* [QNetworkProxy::FtpCachingProxy] = */
364 (int(QNetworkProxy::CachingCapability) |
365 int(QNetworkProxy::HostNameLookupCapability)),
366 };
367
368 Q_ASSERT(int(type) >= 0 && int(type) <= int(QNetworkProxy::FtpCachingProxy));
369 return QNetworkProxy::Capabilities(defaults[int(type)]);
370}
371
372class QNetworkProxyPrivate: public QSharedData
373{
374public:
375 QString hostName;
376 QString user;
377 QString password;
378 QNetworkProxy::Capabilities capabilities;
379 quint16 port;
380 QNetworkProxy::ProxyType type;
381
382 inline QNetworkProxyPrivate(QNetworkProxy::ProxyType t = QNetworkProxy::DefaultProxy,
383 const QString &h = QString(), quint16 p = 0,
384 const QString &u = QString(), const QString &pw = QString())
385 : hostName(h),
386 user(u),
387 password(pw),
388 capabilities(defaultCapabilitiesForType(t)),
389 port(p),
390 type(t)
391 { }
392
393 inline bool operator==(const QNetworkProxyPrivate &other) const
394 {
395 return type == other.type &&
396 port == other.port &&