src/network/kernel/qnetworkproxy.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/network/kernel/qnetworkproxy.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1286 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+/*!
+    \class QNetworkProxy
+
+    \since 4.1
+
+    \brief The QNetworkProxy class provides a network layer proxy.
+
+    \reentrant
+    \ingroup network
+    \inmodule QtNetwork
+
+    QNetworkProxy provides the method for configuring network layer
+    proxy support to the Qt network classes. The currently supported
+    classes are QAbstractSocket, QTcpSocket, QUdpSocket, QTcpServer,
+    QNetworkAccessManager and QFtp. The proxy support is designed to
+    be as transparent as possible. This means that existing
+    network-enabled applications that you have written should
+    automatically support network proxy using the following code.
+
+    \snippet doc/src/snippets/code/src_network_kernel_qnetworkproxy.cpp 0
+
+    An alternative to setting an application wide proxy is to specify
+    the proxy for individual sockets using QAbstractSocket::setProxy()
+    and QTcpServer::setProxy(). In this way, it is possible to disable
+    the use of a proxy for specific sockets using the following code:
+
+    \snippet doc/src/snippets/code/src_network_kernel_qnetworkproxy.cpp 1
+
+    Network proxy is not used if the address used in \l
+    {QAbstractSocket::connectToHost()}{connectToHost()}, \l
+    {QUdpSocket::bind()}{bind()} or \l
+    {QTcpServer::listen()}{listen()} is equivalent to
+    QHostAddress::LocalHost or QHostAddress::LocalHostIPv6.
+
+    Each type of proxy support has certain restrictions associated with it.
+    You should read the \l{ProxyType} documentation carefully before
+    selecting a proxy type to use.
+
+    \note Changes made to currently connected sockets do not take effect.
+    If you need to change a connected socket, you should reconnect it.
+
+    \section1 SOCKS5
+
+    The SOCKS5 support in Qt 4 is based on \l{RFC 1928} and \l{RFC 1929}.
+    The supported authentication methods are no authentication and
+    username/password authentication.  Both IPv4 and IPv6 are
+    supported. Domain names are resolved through the SOCKS5 server if
+    the QNetworkProxy::HostNameLookupCapability is enabled, otherwise
+    they are resolved locally and the IP address is sent to the
+    server. There are several things to remember when using SOCKS5
+    with QUdpSocket and QTcpServer:
+
+    With QUdpSocket, a call to \l {QUdpSocket::bind()}{bind()} may fail
+    with a timeout error. If a port number other than 0 is passed to
+    \l {QUdpSocket::bind()}{bind()}, it is not guaranteed that it is the
+    specified port that will be used.
+    Use \l{QUdpSocket::localPort()}{localPort()} and
+    \l{QUdpSocket::localAddress()}{localAddress()} to get the actual
+    address and port number in use. Because proxied UDP goes through
+    two UDP connections, it is more likely that packets will be dropped.
+
+    With QTcpServer a call to \l{QTcpServer::listen()}{listen()} may
+    fail with a timeout error. If a port number other than 0 is passed
+    to \l{QTcpServer::listen()}{listen()}, then it is not guaranteed
+    that it is the specified port that will be used.
+    Use \l{QTcpServer::serverPort()}{serverPort()} and
+    \l{QTcpServer::serverAddress()}{serverAddress()} to get the actual
+    address and port used to listen for connections. SOCKS5 only supports
+    one accepted connection per call to \l{QTcpServer::listen()}{listen()},
+    and each call is likely to result in a different
+    \l{QTcpServer::serverPort()}{serverPort()} being used.
+
+    \sa QAbstractSocket, QTcpServer
+*/
+
+/*!
+    \enum QNetworkProxy::ProxyType
+
+    This enum describes the types of network proxying provided in Qt.
+
+    There are two types of proxies that Qt understands:
+    transparent proxies and caching proxies. The first group consists
+    of proxies that can handle any arbitrary data transfer, while the
+    second can only handle specific requests. The caching proxies only
+    make sense for the specific classes where they can be used.
+
+    \value NoProxy No proxying is used
+    \value DefaultProxy Proxy is determined based on the application proxy set using setApplicationProxy()
+    \value Socks5Proxy \l Socks5 proxying is used
+    \value HttpProxy HTTP transparent proxying is used
+    \value HttpCachingProxy Proxying for HTTP requests only
+    \value FtpCachingProxy Proxying for FTP requests only
+
+    The table below lists different proxy types and their
+    capabilities. Since each proxy type has different capabilities, it
+    is important to understand them before choosing a proxy type.
+
+    \table
+    \header
+        \o Proxy type
+        \o Description
+        \o Default capabilities
+
+    \row
+        \o SOCKS 5
+        \o Generic proxy for any kind of connection. Supports TCP,
+           UDP, binding to a port (incoming connections) and
+           authentication.
+        \o TunnelingCapability, ListeningCapability,
+           UdpTunnelingCapability, HostNameLookupCapability
+
+    \row
+        \o HTTP
+        \o Implemented using the "CONNECT" command, supports only
+           outgoing TCP connections; supports authentication.
+        \o TunnelingCapability, CachingCapability, HostNameLookupCapability
+
+    \row
+        \o Caching-only HTTP
+        \o Implemented using normal HTTP commands, it is useful only
+           in the context of HTTP requests (see QNetworkAccessManager)
+        \o CachingCapability, HostNameLookupCapability
+
+    \row
+        \o Caching FTP
+        \o Implemented using an FTP proxy, it is useful only in the
+           context of FTP requests (see QFtp,
+           QNetworkAccessManager)
+        \o CachingCapability, HostNameLookupCapability
+
+    \endtable
+
+    Also note that you shouldn't set the application default proxy
+    (setApplicationProxy()) to a proxy that doesn't have the
+    TunnelingCapability capability. If you do, QTcpSocket will not
+    know how to open connections.
+
+    \sa setType(), type(), capabilities(), setCapabilities()
+*/
+
+/*!
+    \enum QNetworkProxy::Capability
+    \since 4.5
+
+    These flags indicate the capabilities that a given proxy server
+    supports.
+
+    QNetworkProxy sets different capabilities by default when the
+    object is created (see QNetworkProxy::ProxyType for a list of the
+    defaults). However, it is possible to change the capabitilies
+    after the object has been created with setCapabilities().
+
+    The capabilities that QNetworkProxy supports are:
+
+    \value TunnelingCapability Ability to open transparent, tunneled
+    TCP connections to a remote host. The proxy server relays the
+    transmission verbatim from one side to the other and does no
+    caching.
+
+    \value ListeningCapability Ability to create a listening socket
+    and wait for an incoming TCP connection from a remote host.
+
+    \value UdpTunnelingCapability Ability to relay UDP datagrams via
+    the proxy server to and from a remote host.
+
+    \value CachingCapability Ability to cache the contents of the
+    transfer. This capability is specific to each protocol and proxy
+    type. For example, HTTP proxies can cache the contents of web data
+    transferred with "GET" commands.
+
+    \value HostNameLookupCapability Ability to connect to perform the
+    lookup on a remote host name and connect to it, as opposed to
+    requiring the application to perform the name lookup and request
+    connection to IP addresses only.
+*/
+
+#include "qnetworkproxy.h"
+
+#ifndef QT_NO_NETWORKPROXY
+
+#include "private/qnetworkproxy_p.h"
+#include "private/qsocks5socketengine_p.h"
+#include "private/qhttpsocketengine_p.h"
+#include "qauthenticator.h"
+#include "qhash.h"
+#include "qmutex.h"
+#include "qurl.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSocks5SocketEngineHandler;
+class QHttpSocketEngineHandler;
+
+class QGlobalNetworkProxy
+{
+public:
+    QGlobalNetworkProxy()
+        : mutex(QMutex::Recursive)
+        , applicationLevelProxy(0)
+        , applicationLevelProxyFactory(0)
+        , socks5SocketEngineHandler(0)
+        , httpSocketEngineHandler(0)
+    {
+    }
+
+    ~QGlobalNetworkProxy()
+    {
+        delete applicationLevelProxy;
+        delete applicationLevelProxyFactory;
+        delete socks5SocketEngineHandler;
+        delete httpSocketEngineHandler;
+    }
+
+    void init()
+    {
+        QMutexLocker lock(&mutex);
+#ifndef QT_NO_SOCKS5
+        if (!socks5SocketEngineHandler)
+            socks5SocketEngineHandler = new QSocks5SocketEngineHandler();
+#endif
+#ifndef QT_NO_HTTP
+        if (!httpSocketEngineHandler)
+            httpSocketEngineHandler = new QHttpSocketEngineHandler();
+#endif
+    }
+
+    void setApplicationProxy(const QNetworkProxy &proxy)
+    {
+        QMutexLocker lock(&mutex);
+        if (!applicationLevelProxy)
+            applicationLevelProxy = new QNetworkProxy;
+        *applicationLevelProxy = proxy;
+        delete applicationLevelProxyFactory;
+        applicationLevelProxyFactory = 0;
+    }
+
+    void setApplicationProxyFactory(QNetworkProxyFactory *factory)
+    {
+        QMutexLocker lock(&mutex);
+        if (applicationLevelProxy)
+            *applicationLevelProxy = QNetworkProxy();
+        delete applicationLevelProxyFactory;
+        applicationLevelProxyFactory = factory;
+    }
+
+    QNetworkProxy applicationProxy()
+    {
+        return proxyForQuery(QNetworkProxyQuery()).first();
+    }
+
+    QList<QNetworkProxy> proxyForQuery(const QNetworkProxyQuery &query);
+
+private:
+    QMutex mutex;
+    QNetworkProxy *applicationLevelProxy;
+    QNetworkProxyFactory *applicationLevelProxyFactory;
+    QSocks5SocketEngineHandler *socks5SocketEngineHandler;
+    QHttpSocketEngineHandler *httpSocketEngineHandler;
+};
+
+QList<QNetworkProxy> QGlobalNetworkProxy::proxyForQuery(const QNetworkProxyQuery &query)
+{
+    QMutexLocker locker(&mutex);
+
+    QList<QNetworkProxy> result;
+    if (!applicationLevelProxyFactory) {
+        if (applicationLevelProxy
+            && applicationLevelProxy->type() != QNetworkProxy::DefaultProxy)
+            result << *applicationLevelProxy;
+        else
+            result << QNetworkProxy(QNetworkProxy::NoProxy);
+        return result;
+    }
+
+    // we have a factory
+    result = applicationLevelProxyFactory->queryProxy(query);
+    if (result.isEmpty()) {
+        qWarning("QNetworkProxyFactory: factory %p has returned an empty result set",
+                 applicationLevelProxyFactory);
+        result << QNetworkProxy(QNetworkProxy::NoProxy);
+    }
+    return result;
+}
+
+Q_GLOBAL_STATIC(QGlobalNetworkProxy, globalNetworkProxy)
+
+namespace {
+    template<bool> struct StaticAssertTest;
+    template<> struct StaticAssertTest<true> { enum { Value = 1 }; };
+}
+
+static inline void qt_noop_with_arg(int) {}
+#define q_static_assert(expr)   qt_noop_with_arg(sizeof(StaticAssertTest< expr >::Value))
+
+static QNetworkProxy::Capabilities defaultCapabilitiesForType(QNetworkProxy::ProxyType type)
+{
+    q_static_assert(int(QNetworkProxy::DefaultProxy) == 0);
+    q_static_assert(int(QNetworkProxy::FtpCachingProxy) == 5);
+    static const int defaults[] =
+    {
+        /* [QNetworkProxy::DefaultProxy] = */
+        (int(QNetworkProxy::ListeningCapability) |
+         int(QNetworkProxy::TunnelingCapability) |
+         int(QNetworkProxy::UdpTunnelingCapability)),
+        /* [QNetworkProxy::Socks5Proxy] = */
+        (int(QNetworkProxy::TunnelingCapability) |
+         int(QNetworkProxy::ListeningCapability) |
+         int(QNetworkProxy::UdpTunnelingCapability) |
+         int(QNetworkProxy::HostNameLookupCapability)),
+        // it's weird to talk about the proxy capabilities of a "not proxy"...
+        /* [QNetworkProxy::NoProxy] = */
+        (int(QNetworkProxy::ListeningCapability) |
+         int(QNetworkProxy::TunnelingCapability) |
+         int(QNetworkProxy::UdpTunnelingCapability)),
+        /* [QNetworkProxy::HttpProxy] = */
+        (int(QNetworkProxy::TunnelingCapability) |
+         int(QNetworkProxy::CachingCapability) |
+         int(QNetworkProxy::HostNameLookupCapability)),
+        /* [QNetworkProxy::HttpCachingProxy] = */
+        (int(QNetworkProxy::CachingCapability) |
+         int(QNetworkProxy::HostNameLookupCapability)),
+        /* [QNetworkProxy::FtpCachingProxy] = */
+        (int(QNetworkProxy::CachingCapability) |
+         int(QNetworkProxy::HostNameLookupCapability)),
+    };
+
+    if (int(type) < 0 || int(type) > int(QNetworkProxy::FtpCachingProxy))
+        type = QNetworkProxy::DefaultProxy;
+    return QNetworkProxy::Capabilities(defaults[int(type)]);
+}
+
+class QNetworkProxyPrivate: public QSharedData
+{
+public:
+    QString hostName;
+    QString user;
+    QString password;
+    QNetworkProxy::Capabilities capabilities;
+    quint16 port;
+    QNetworkProxy::ProxyType type;
+    bool capabilitiesSet;
+
+    inline QNetworkProxyPrivate(QNetworkProxy::ProxyType t = QNetworkProxy::DefaultProxy,
+                                const QString &h = QString(), quint16 p = 0,
+                                const QString &u = QString(), const QString &pw = QString())
+        : hostName(h),
+          user(u),
+          password(pw),
+          capabilities(defaultCapabilitiesForType(t)),
+          port(p),
+          type(t),
+          capabilitiesSet(false)
+    { }
+
+    inline bool operator==(const QNetworkProxyPrivate &other) const
+    {
+        return type == other.type &&
+            port == other.port &&
+            hostName == other.hostName &&
+            user == other.user &&
+            password == other.password &&
+            capabilities == other.capabilities;
+    }
+};
+
+template<> void QSharedDataPointer<QNetworkProxyPrivate>::detach()
+{
+    if (d && d->ref == 1)
+        return;
+    QNetworkProxyPrivate *x = (d ? new QNetworkProxyPrivate(*d)
+                               : new QNetworkProxyPrivate);
+    x->ref.ref();
+    if (d && !d->ref.deref())
+        delete d;
+    d = x;
+}
+
+/*!
+    Constructs a QNetworkProxy with DefaultProxy type; the proxy type is
+    determined by applicationProxy(), which defaults to NoProxy.
+
+    \sa setType(), setApplicationProxy()
+*/
+QNetworkProxy::QNetworkProxy()
+    : d(0)
+{
+    globalNetworkProxy()->init();
+}
+
+/*!
+    Constructs a QNetworkProxy with \a type, \a hostName, \a port,
+    \a user and \a password.
+
+    The default capabilities for proxy type \a type are set automatically.
+
+    \sa capabilities()
+*/
+QNetworkProxy::QNetworkProxy(ProxyType type, const QString &hostName, quint16 port,
+                  const QString &user, const QString &password)
+    : d(new QNetworkProxyPrivate(type, hostName, port, user, password))
+{
+    globalNetworkProxy()->init();
+}
+
+/*!
+    Constructs a copy of \a other.
+*/
+QNetworkProxy::QNetworkProxy(const QNetworkProxy &other)
+    : d(other.d)
+{
+}
+
+/*!
+    Destroys the QNetworkProxy object.
+*/
+QNetworkProxy::~QNetworkProxy()
+{
+    // QSharedDataPointer takes care of deleting for us
+}
+
+/*!
+    \since 4.4
+
+    Compares the value of this network proxy to \a other and returns true
+    if they are equal (same proxy type, server as well as username and password)
+*/
+bool QNetworkProxy::operator==(const QNetworkProxy &other) const
+{
+    return d == other.d || (d && other.d && *d == *other.d);
+}
+
+/*!
+    \fn bool QNetworkProxy::operator!=(const QNetworkProxy &other) const
+    \since 4.4
+
+    Compares the value of this network proxy to \a other and returns true
+    if they differ.
+\*/
+
+/*!
+    \since 4.2
+
+    Assigns the value of the network proxy \a other to this network proxy.
+*/
+QNetworkProxy &QNetworkProxy::operator=(const QNetworkProxy &other)
+{
+    d = other.d;
+    return *this;
+}
+
+/*!
+    Sets the proxy type for this instance to be \a type.
+
+    Note that changing the type of a proxy does not change
+    the set of capabilities this QNetworkProxy object holds if any
+    capabilities have been set with setCapabilities().
+
+    \sa type(), setCapabilities()
+*/
+void QNetworkProxy::setType(QNetworkProxy::ProxyType type)
+{
+    d->type = type;
+    if (!d->capabilitiesSet)
+        d->capabilities = defaultCapabilitiesForType(type);
+}
+
+/*!
+    Returns the proxy type for this instance.
+
+    \sa setType()
+*/
+QNetworkProxy::ProxyType QNetworkProxy::type() const
+{
+    return d ? d->type : DefaultProxy;
+}
+
+/*!
+    \since 4.5
+
+    Sets the capabilities of this proxy to \a capabilities.
+
+    \sa setType(), capabilities()
+*/
+void QNetworkProxy::setCapabilities(Capabilities capabilities)
+{
+    d->capabilities = capabilities;
+    d->capabilitiesSet = true;
+}
+
+/*!
+    \since 4.5
+
+    Returns the capabilities of this proxy server.
+
+    \sa setCapabilities(), type()
+*/
+QNetworkProxy::Capabilities QNetworkProxy::capabilities() const
+{
+    return d ? d->capabilities : defaultCapabilitiesForType(DefaultProxy);
+}
+
+/*!
+    \since 4.4
+
+    Returns true if this proxy supports the
+    QNetworkProxy::CachingCapability capability.
+
+    In Qt 4.4, the capability was tied to the proxy type, but since Qt
+    4.5 it is possible to remove the capability of caching from a
+    proxy by calling setCapabilities().
+
+    \sa capabilities(), type(), isTransparentProxy()
+*/
+bool QNetworkProxy::isCachingProxy() const
+{
+    return capabilities() & CachingCapability;
+}
+
+/*!
+    \since 4.4
+
+    Returns true if this proxy supports transparent tunneling of TCP
+    connections. This matches the QNetworkProxy::TunnelingCapability
+    capability.
+
+    In Qt 4.4, the capability was tied to the proxy type, but since Qt
+    4.5 it is possible to remove the capability of caching from a
+    proxy by calling setCapabilities().
+
+    \sa capabilities(), type(), isCachingProxy()
+*/
+bool QNetworkProxy::isTransparentProxy() const
+{
+    return capabilities() & TunnelingCapability;
+}
+
+/*!
+    Sets the user name for proxy authentication to be \a user.
+
+    \sa user(), setPassword(), password()
+*/
+void QNetworkProxy::setUser(const QString &user)
+{
+    d->user = user;
+}
+
+/*!
+    Returns the user name used for authentication.
+
+    \sa setUser(), setPassword(), password()
+*/
+QString QNetworkProxy::user() const
+{
+    return d ? d->user : QString();
+}
+
+/*!
+    Sets the password for proxy authentication to be \a password.
+
+    \sa user(), setUser(), password()
+*/
+void QNetworkProxy::setPassword(const QString &password)
+{
+    d->password = password;
+}
+
+/*!
+    Returns the password used for authentication.
+
+    \sa user(), setPassword(), setUser()
+*/
+QString QNetworkProxy::password() const
+{
+    return d ? d->password : QString();
+}
+
+/*!
+    Sets the host name of the proxy host to be \a hostName.
+
+    \sa hostName(), setPort(), port()
+*/
+void QNetworkProxy::setHostName(const QString &hostName)
+{
+    d->hostName = hostName;
+}
+
+/*!
+    Returns the host name of the proxy host.
+
+    \sa setHostName(), setPort(), port()
+*/
+QString QNetworkProxy::hostName() const
+{
+    return d ? d->hostName : QString();
+}
+
+/*!
+    Sets the port of the proxy host to be \a port.
+
+    \sa hostName(), setHostName(), port()
+*/
+void QNetworkProxy::setPort(quint16 port)
+{
+    d->port = port;
+}
+
+/*!
+    Returns the port of the proxy host.
+
+    \sa setHostName(), setPort(), hostName()
+*/
+quint16 QNetworkProxy::port() const
+{
+    return d ? d->port : 0;
+}
+
+/*!
+    Sets the application level network proxying to be \a networkProxy.
+
+    If a QAbstractSocket or QTcpSocket has the
+    QNetworkProxy::DefaultProxy type, then the QNetworkProxy set with
+    this function is used. If you want more flexibility in determining
+    which the proxy, use the QNetworkProxyFactory class.
+
+    Setting a default proxy value with this function will override the
+    application proxy factory set with
+    QNetworkProxyFactory::setApplicationProxyFactory.
+
+    \sa QNetworkProxyFactory, applicationProxy(), QAbstractSocket::setProxy(), QTcpServer::setProxy()
+*/
+void QNetworkProxy::setApplicationProxy(const QNetworkProxy &networkProxy)
+{
+    if (globalNetworkProxy()) {
+        // don't accept setting the proxy to DefaultProxy
+        if (networkProxy.type() == DefaultProxy)
+            globalNetworkProxy()->setApplicationProxy(QNetworkProxy::NoProxy);
+        else
+            globalNetworkProxy()->setApplicationProxy(networkProxy);
+    }
+}
+
+/*!
+    Returns the application level network proxying.
+
+    If a QAbstractSocket or QTcpSocket has the
+    QNetworkProxy::DefaultProxy type, then the QNetworkProxy returned
+    by this function is used.
+
+    \sa QNetworkProxyFactory, setApplicationProxy(), QAbstractSocket::proxy(), QTcpServer::proxy()
+*/
+QNetworkProxy QNetworkProxy::applicationProxy()
+{
+    if (globalNetworkProxy())
+        return globalNetworkProxy()->applicationProxy();
+    return QNetworkProxy();
+}
+
+class QNetworkProxyQueryPrivate: public QSharedData
+{
+public:
+    inline QNetworkProxyQueryPrivate()
+        : localPort(-1), type(QNetworkProxyQuery::TcpSocket)
+    { }
+
+    bool operator==(const QNetworkProxyQueryPrivate &other) const
+    {
+        return type == other.type &&
+            localPort == other.localPort &&
+            remote == other.remote;
+    }
+
+    QUrl remote;
+    int localPort;
+    QNetworkProxyQuery::QueryType type;
+};
+
+template<> void QSharedDataPointer<QNetworkProxyQueryPrivate>::detach()
+{
+    if (d && d->ref == 1)
+        return;
+    QNetworkProxyQueryPrivate *x = (d ? new QNetworkProxyQueryPrivate(*d)
+                                    : new QNetworkProxyQueryPrivate);
+    x->ref.ref();
+    if (d && !d->ref.deref())
+        delete d;
+    d = x;
+}
+
+/*!
+    \class QNetworkProxyQuery
+    \since 4.5
+    \inmodule QtNetwork
+    \brief The QNetworkProxyQuery class is used to query the proxy
+    settings for a socket
+
+    QNetworkProxyQuery holds the details of a socket being created or
+    request being made. It is used by QNetworkProxy and
+    QNetworkProxyFactory to allow applications to have a more
+    fine-grained control over which proxy servers are used, depending
+    on the details of the query. This allows an application to apply
+    different settings, according to the protocol or destination
+    hostname, for instance.
+
+    QNetworkProxyQuery supports the following criteria for selecting
+    the proxy:
+
+    \list
+      \o the type of query
+      \o the local port number to use
+      \o the destination host name
+      \o the destination port number
+      \o the protocol name, such as "http" or "ftp"
+      \o the URL being requested
+    \endlist
+
+    The destination host name is the host in the connection in the
+    case of outgoing connection sockets. It is the \c hostName
+    parameter passed to QTcpSocket::connectToHost() or the host
+    component of a URL requested with QNetworkRequest.
+
+    The destination port number is the requested port to connect to in
+    the case of outgoing sockets, while the local port number is the
+    port the socket wishes to use locally before attempting the
+    external connection. In most cases, the local port number is used
+    by listening sockets only (QTcpSocket) or by datagram sockets
+    (QUdpSocket).
+
+    The protocol name is an arbitrary string that indicates the type
+    of connection being attempted. For example, it can match the
+    scheme of a URL, like "http", "https" and "ftp". In most cases,
+    the proxy selection will not change depending on the protocol, but
+    this information is provided in case a better choice can be made,
+    like choosing an caching HTTP proxy for HTTP-based connections,
+    but a more powerful SOCKSv5 proxy for all others.
+
+    Some of the criteria may not make sense in all of the types of
+    query. The following table lists the criteria that are most
+    commonly used, according to the type of query.
+
+    \table
+    \header
+      \o Query type
+      \o Description
+
+    \row
+      \o TcpSocket
+      \o Normal sockets requesting a connection to a remote server,
+         like QTcpSocket. The peer hostname and peer port match the
+         values passed to QTcpSocket::connectToHost(). The local port
+         is usually -1, indicating the socket has no preference in
+         which port should be used. The URL component is not used.
+
+    \row
+      \o UdpSocket
+      \o Datagram-based sockets, which can both send and
+         receive. The local port, remote host or remote port fields
+         can all be used or be left unused, depending on the
+         characteristics of the socket. The URL component is not used.
+
+    \row
+      \o TcpServer
+      \o Passive server sockets that listen on a port and await
+         incoming connections from the network. Normally, only the
+         local port is used, but the remote address could be used in
+         specific circumstances, for example to indicate which remote
+         host a connection is expected from. The URL component is not used.
+
+    \row
+      \o UrlRequest
+      \o A more high-level request, such as those coming from
+         QNetworkAccessManager. These requests will inevitably use an
+         outgoing TCP socket, but the this query type is provided to
+         indicate that more detailed information is present in the URL
+         component. For ease of implementation, the URL's host and
+         port are set as the destination address.
+    \endtable
+
+    It should be noted that any of the criteria may be missing or
+    unknown (an empty QString for the hostname or protocol name, -1
+    for the port numbers). If that happens, the functions executing
+    the query should make their best guess or apply some
+    implementation-defined default values.
+
+    \sa QNetworkProxy, QNetworkProxyFactory, QNetworkAccessManager,
+        QAbstractSocket::setProxy()
+*/
+
+/*!
+    \enum QNetworkProxyQuery::QueryType
+
+    Describes the type of one QNetworkProxyQuery query.
+
+    \value TcpSocket    a normal, outgoing TCP socket
+    \value UdpSocket    a datagram-based UDP socket, which could send
+                        to multiple destinations
+    \value TcpServer    a TCP server that listens for incoming
+                        connections from the network
+    \value UrlRequest   a more complex request which involves loading
+                        of a URL
+
+    \sa queryType(), setQueryType()
+*/
+
+/*!
+    Constructs a default QNetworkProxyQuery object. By default, the
+    query type will be QNetworkProxyQuery::TcpSocket.
+*/
+QNetworkProxyQuery::QNetworkProxyQuery()
+{
+}
+
+/*!
+    Constructs a QNetworkProxyQuery with the URL \a requestUrl and
+    sets the query type to \a queryType.
+
+    \sa protocolTag(), peerHostName(), peerPort()
+*/
+QNetworkProxyQuery::QNetworkProxyQuery(const QUrl &requestUrl, QueryType queryType)
+{
+    d->remote = requestUrl;
+    d->type = queryType;
+}
+
+/*!
+    Constructs a QNetworkProxyQuery of type \a queryType and sets the
+    protocol tag to be \a protocolTag. This constructor is suitable
+    for QNetworkProxyQuery::TcpSocket queries, because it sets the
+    peer hostname to \a hostname and the peer's port number to \a
+    port.
+*/
+QNetworkProxyQuery::QNetworkProxyQuery(const QString &hostname, int port,
+                                       const QString &protocolTag,
+                                       QueryType queryType)
+{
+    d->remote.setScheme(protocolTag);
+    d->remote.setHost(hostname);
+    d->remote.setPort(port);
+    d->type = queryType;
+}
+
+/*!
+    Constructs a QNetworkProxyQuery of type \a queryType and sets the
+    protocol tag to be \a protocolTag. This constructor is suitable
+    for QNetworkProxyQuery::TcpSocket queries because it sets the
+    local port number to \a bindPort.
+
+    Note that \a bindPort is of type quint16 to indicate the exact
+    port number that is requested. The value of -1 (unknown) is not
+    allowed in this context.
+
+    \sa localPort()
+*/
+QNetworkProxyQuery::QNetworkProxyQuery(quint16 bindPort, const QString &protocolTag,
+                                       QueryType queryType)
+{
+    d->remote.setScheme(protocolTag);
+    d->localPort = bindPort;
+    d->type = queryType;
+}
+
+/*!
+    Constructs a QNetworkProxyQuery object that is a copy of \a other.
+*/
+QNetworkProxyQuery::QNetworkProxyQuery(const QNetworkProxyQuery &other)
+    : d(other.d)
+{
+}
+
+/*!
+    Destroys this QNetworkProxyQuery object.
+*/
+QNetworkProxyQuery::~QNetworkProxyQuery()
+{
+    // QSharedDataPointer automatically deletes
+}
+
+/*!
+    Copies the contents of \a other.
+*/
+QNetworkProxyQuery &QNetworkProxyQuery::operator=(const QNetworkProxyQuery &other)
+{
+    d = other.d;
+    return *this;
+}
+
+/*!
+    Returns true if this QNetworkProxyQuery object contains the same
+    data as \a other.
+*/
+bool QNetworkProxyQuery::operator==(const QNetworkProxyQuery &other) const
+{
+    return d == other.d || (d && other.d && *d == *other.d);
+}
+
+/*!
+    \fn bool QNetworkProxyQuery::operator!=(const QNetworkProxyQuery &other) const
+
+    Returns true if this QNetworkProxyQuery object does not contain
+    the same data as \a other.
+*/
+
+/*!
+    Returns the query type.
+*/
+QNetworkProxyQuery::QueryType QNetworkProxyQuery::queryType() const
+{
+    return d ? d->type : TcpSocket;
+}
+
+/*!
+    Sets the query type of this object to be \a type.
+*/
+void QNetworkProxyQuery::setQueryType(QueryType type)
+{
+    d->type = type;
+}
+
+/*!
+    Returns the port number for the outgoing request or -1 if the port
+    number is not known.
+
+    If the query type is QNetworkProxyQuery::UrlRequest, this function
+    returns the port number of the URL being requested. In general,
+    frameworks will fill in the port number from their default values.
+
+    \sa peerHostName(), localPort(), setPeerPort()
+*/
+int QNetworkProxyQuery::peerPort() const
+{
+    return d ? d->remote.port() : -1;
+}
+
+/*!
+    Sets the requested port number for the outgoing connection to be
+    \a port. Valid values are 1 to 65535, or -1 to indicate that the
+    remote port number is unknown.
+
+    The peer port number can also be used to indicate the expected
+    port number of an incoming connection in the case of
+    QNetworkProxyQuery::UdpSocket or QNetworkProxyQuery::TcpServer
+    query types.
+
+    \sa peerPort(), setPeerHostName(), setLocalPort()
+*/
+void QNetworkProxyQuery::setPeerPort(int port)
+{
+    d->remote.setPort(port);
+}
+
+/*!
+    Returns the host name or IP address being of the outgoing
+    connection being requested, or an empty string if the remote
+    hostname is not known.
+
+    If the query type is QNetworkProxyQuery::UrlRequest, this function
+    returns the host component of the URL being requested.
+
+    \sa peerPort(), localPort(), setPeerHostName()
+*/
+QString QNetworkProxyQuery::peerHostName() const
+{
+    return d ? d->remote.host() : QString();
+}
+
+/*!
+    Sets the hostname of the outgoing connection being requested to \a
+    hostname.  An empty hostname can be used to indicate that the
+    remote host is unknown.
+
+    The peer host name can also be used to indicate the expected
+    source address of an incoming connection in the case of
+    QNetworkProxyQuery::UdpSocket or QNetworkProxyQuery::TcpServer
+    query types.
+
+    \sa peerHostName(), setPeerPort(), setLocalPort()
+*/
+void QNetworkProxyQuery::setPeerHostName(const QString &hostname)
+{
+    d->remote.setHost(hostname);
+}
+
+/*!
+    Returns the port number of the socket that will accept incoming
+    packets from remote servers or -1 if the port is not known.
+
+    \sa peerPort(), peerHostName(), setLocalPort()
+*/
+int QNetworkProxyQuery::localPort() const
+{
+    return d ? d->localPort : -1;
+}
+
+/*!
+    Sets the port number that the socket wishes to use locally to
+    accept incoming packets from remote servers to \a port. The local
+    port is most often used with the QNetworkProxyQuery::TcpServer
+    and QNetworkProxyQuery::UdpSocket query types.
+
+    Valid values are 0 to 65535 (with 0 indicating that any port
+    number will be acceptable) or -1, which means the local port
+    number is unknown or not applicable.
+
+    In some circumstances, for special protocols, it's the local port
+    number can also be used with a query of type
+    QNetworkProxyQuery::TcpSocket. When that happens, the socket is
+    indicating it wishes to use the port number \a port when
+    connecting to a remote host.
+
+    \sa localPort(), setPeerPort(), setPeerHostName()
+*/
+void QNetworkProxyQuery::setLocalPort(int port)
+{
+    d->localPort = port;
+}
+
+/*!
+    Returns the protocol tag for this QNetworkProxyQuery object, or an
+    empty QString in case the protocol tag is unknown.
+
+    In the case of queries of type QNetworkProxyQuery::UrlRequest,
+    this function returns the value of the scheme component of the
+    URL.
+
+    \sa setProtocolTag(), url()
+*/
+QString QNetworkProxyQuery::protocolTag() const
+{
+    return d ? d->remote.scheme() : QString();
+}
+
+/*!
+    Sets the protocol tag for this QNetworkProxyQuery object to be \a
+    protocolTag.
+
+    The protocol tag is an arbitrary string that indicates which
+    protocol is being talked over the socket, such as "http", "xmpp",
+    "telnet", etc. The protocol tag is used by the backend to
+    return a request that is more specific to the protocol in
+    question: for example, a HTTP connection could be use a caching
+    HTTP proxy server, while all other connections use a more powerful
+    SOCKSv5 proxy server.
+
+    \sa protocolTag()
+*/
+void QNetworkProxyQuery::setProtocolTag(const QString &protocolTag)
+{
+    d->remote.setScheme(protocolTag);
+}
+
+/*!
+    Returns the URL component of this QNetworkProxyQuery object in
+    case of a query of type QNetworkProxyQuery::UrlRequest.
+
+    \sa setUrl()
+*/
+QUrl QNetworkProxyQuery::url() const
+{
+    return d ? d->remote : QUrl();
+}
+
+/*!
+    Sets the URL component of this QNetworkProxyQuery object to be \a
+    url. Setting the URL will also set the protocol tag, the remote
+    host name and port number. This is done so as to facilitate the
+    implementation of the code that determines the proxy server to be
+    used.
+
+    \sa url(), peerHostName(), peerPort()
+*/
+void QNetworkProxyQuery::setUrl(const QUrl &url)
+{
+    d->remote = url;
+}
+
+/*!
+    \class QNetworkProxyFactory
+    \brief The QNetworkProxyFactory class provides fine-grained proxy selection.
+    \since 4.5
+
+    \ingroup network
+    \inmodule QtNetwork
+
+    QNetworkProxyFactory is an extension to QNetworkProxy, allowing
+    applications to have a more fine-grained control over which proxy
+    servers are used, depending on the socket requesting the
+    proxy. This allows an application to apply different settings,
+    according to the protocol or destination hostname, for instance.
+
+    QNetworkProxyFactory can be set globally for an application, in
+    which case it will override any global proxies set with
+    QNetworkProxy::setApplicationProxy(). If set globally, any sockets
+    created with Qt will query the factory to determine the proxy to
+    be used.
+
+    A factory can also be set in certain frameworks that support
+    multiple connections, such as QNetworkAccessManager. When set on
+    such object, the factory will be queried for sockets created by
+    that framework only.
+*/
+
+/*!
+    Creates a QNetworkProxyFactory object.
+
+    Since QNetworkProxyFactory is an abstract class, you cannot create
+    objects of type QNetworkProxyFactory directly.
+*/
+QNetworkProxyFactory::QNetworkProxyFactory()
+{
+}
+
+/*!
+    Destroys the QNetworkProxyFactory object.
+*/
+QNetworkProxyFactory::~QNetworkProxyFactory()
+{
+}
+
+
+/*!
+    Enables the use of the platform-specific proxy settings, and only those.
+    See systemProxyForQuery() for more information.
+
+    Internally, this method (when called with \a enable set to true)
+    sets an application-wide proxy factory. For this reason, this method
+    is mutually exclusive with setApplicationProxyFactory: calling
+    setApplicationProxyFactory overrides the use of the system-wide proxy,
+    and calling setUseSystemConfiguration overrides any
+    application proxy or proxy factory that was previously set.
+
+    \since 4.6
+*/
+void QNetworkProxyFactory::setUseSystemConfiguration(bool enable)
+{
+    if (enable) {
+        setApplicationProxyFactory(new QSystemConfigurationProxyFactory);
+    } else {
+        setApplicationProxyFactory(0);
+    }
+}
+
+/*!
+    Sets the application-wide proxy factory to be \a factory. This
+    function will take ownership of that object and will delete it
+    when necessary.
+
+    The application-wide proxy is used as a last-resort when all other
+    proxy selection requests returned QNetworkProxy::DefaultProxy. For
+    example, QTcpSocket objects can have a proxy set with
+    QTcpSocket::setProxy, but if none is set, the proxy factory class
+    set with this function will be queried.
+
+    If you set a proxy factory with this function, any application
+    level proxies set with QNetworkProxy::setApplicationProxy will be
+    overridden.
+
+    \sa QNetworkProxy::setApplicationProxy(),
+        QAbstractSocket::proxy(), QAbstractSocket::setProxy()
+*/
+void QNetworkProxyFactory::setApplicationProxyFactory(QNetworkProxyFactory *factory)
+{
+    if (globalNetworkProxy())
+        globalNetworkProxy()->setApplicationProxyFactory(factory);
+}
+
+/*!
+    \fn QList<QNetworkProxy> QNetworkProxyFactory::queryProxy(const QNetworkProxyQuery &query)
+
+    This function examines takes the query request, \a query,
+    examines the details of the type of socket or request and returns
+    a list of QNetworkProxy objects that indicate the proxy servers to
+    be used, in order of preference.
+
+    When reimplementing this class, take care to return at least one
+    element.
+
+    If you cannot determine a better proxy alternative, use
+    QNetworkProxy::DefaultProxy, which tells the code querying for a
+    proxy to use a higher alternative. For example, if this factory is
+    set to a QNetworkAccessManager object, DefaultProxy will tell it
+    to query the application-level proxy settings.
+
+    If this factory is set as the application proxy factory,
+    DefaultProxy and NoProxy will have the same meaning.
+*/
+
+/*!
+    \fn QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &query)
+
+    This function examines takes the query request, \a query,
+    examines the details of the type of socket or request and returns
+    a list of QNetworkProxy objects that indicate the proxy servers to
+    be used, in order of preference.
+
+    This function can be used to determine the platform-specific proxy
+    settings. This function will use the libraries provided by the
+    operating system to determine the proxy for a given connection, if
+    such libraries exist. If they don't, this function will just return a
+    QNetworkProxy of type QNetworkProxy::NoProxy.
+
+    On Windows, this function will use the WinHTTP DLL functions. Despite
+    its name, Microsoft suggests using it for all applications that
+    require network connections, not just HTTP. This will respect the
+    proxy settings set on the registry with the proxycfg.exe tool. If
+    those settings are not found, this function will attempt to obtain
+    Internet Explorer's settings and use them.
+
+    On MacOS X, this function will obtain the proxy settings using the
+    SystemConfiguration framework from Apple. It will apply the FTP,
+    HTTP and HTTPS proxy configurations for queries that contain the
+    protocol tag "ftp", "http" and "https", respectively. If the SOCKS
+    proxy is enabled in that configuration, this function will use the
+    SOCKS server for all queries. If SOCKS isn't enabled, it will use
+    the HTTPS proxy for all TcpSocket and UrlRequest queries.
+
+    On other systems, there is no standardised method of obtaining the
+    system proxy configuration. This function may be improved in
+    future versions to support those systems.
+
+    \section1 Limitations
+
+    These are the limitations for the current version of this
+    function. Future versions of Qt may lift some of the limitations
+    listed here.
+
+    On MacOS X, this function will ignore the Proxy Auto Configuration
+    settings, since it cannot execute the associated ECMAScript code.
+*/
+
+/*!
+    This function examines takes the query request, \a query,
+    examines the details of the type of socket or request and returns
+    a list of QNetworkProxy objects that indicate the proxy servers to
+    be used, in order of preference.
+*/
+QList<QNetworkProxy> QNetworkProxyFactory::proxyForQuery(const QNetworkProxyQuery &query)
+{
+    if (!globalNetworkProxy())
+        return QList<QNetworkProxy>() << QNetworkProxy(QNetworkProxy::NoProxy);
+    return globalNetworkProxy()->proxyForQuery(query);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_NETWORKPROXY