From 3430e7ce7787cf1c1b1472a0ce0e8770dbff0a7c Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Tue, 27 Jan 2015 18:41:32 +0100 Subject: Add libproxy backend for QNetworkProxyFactory It will be used on Unix systems if the required dev package is present. (Detected by a configure compile test.) You can configure with -no-libproxy to avoid the dependency. It will not be used on OS X or Windows, as we already implement the native API for getting proxies there. Currently we use whatever PAC runner is provided by the distro for running PAC scripts - if we want to run PAC scripts using Qt, then we would have to implement a pacrunner plugin to libproxy. Note that their webkit pacrunner is using javascriptcore already. Tested using the libproxy 0.4.7 that is included in Ubuntu 12.04. Re-tested using Ubuntu 14.04 which ships libproxy 0.4.11. It works except when both socks and http proxies are configured in the manual settings - in that case libproxy returns only the socks proxy. This seems to be covered by libproxy issue 119. [ChangeLog][QtNetwork] Introduce libproxy backend for Unix platforms, enabled automatically if the required dev package is present Task-number: QTBUG-26295 Change-Id: I521c0a198fcf482386ea8a189114a0077778265c Reviewed-by: Richard J. Moore --- config.tests/common/libproxy/libproxy.cpp | 59 +++++++++ config.tests/common/libproxy/libproxy.pro | 4 + configure | 32 +++++ src/network/kernel/kernel.pri | 11 +- src/network/kernel/qnetworkproxy_libproxy.cpp | 165 ++++++++++++++++++++++++++ tools/configure/configureapp.cpp | 15 +++ 6 files changed, 283 insertions(+), 3 deletions(-) create mode 100644 config.tests/common/libproxy/libproxy.cpp create mode 100644 config.tests/common/libproxy/libproxy.pro create mode 100644 src/network/kernel/qnetworkproxy_libproxy.cpp diff --git a/config.tests/common/libproxy/libproxy.cpp b/config.tests/common/libproxy/libproxy.cpp new file mode 100644 index 0000000000..cd366f52ee --- /dev/null +++ b/config.tests/common/libproxy/libproxy.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the config.tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +int main(int, char **) +{ + pxProxyFactory *factory = px_proxy_factory_new(); + char **proxies = px_proxy_factory_get_proxies(factory, "http://qt-project.org"); + if (proxies) { + for (int i = 0; proxies[i]; i++) { + printf("%s\n", proxies[i]); + free(proxies[i]); + } + free(proxies); + } + px_proxy_factory_free(factory); + return 0; +} diff --git a/config.tests/common/libproxy/libproxy.pro b/config.tests/common/libproxy/libproxy.pro new file mode 100644 index 0000000000..51de2021ff --- /dev/null +++ b/config.tests/common/libproxy/libproxy.pro @@ -0,0 +1,4 @@ +SOURCES = libproxy.cpp +CONFIG -= qt dylib +mac:CONFIG -= app_bundle +LIBS += -lproxy diff --git a/configure b/configure index ebb2057cc6..835cb9e58f 100755 --- a/configure +++ b/configure @@ -681,6 +681,7 @@ CFG_GLIB=auto CFG_QGTKSTYLE=auto CFG_LARGEFILE=auto CFG_OPENSSL=auto +CFG_LIBPROXY=auto CFG_SECURETRANSPORT=auto CFG_PRECOMPILE=auto CFG_SEPARATE_DEBUG_INFO=no @@ -1980,6 +1981,13 @@ while [ "$#" -gt 0 ]; do UNKNOWN_OPT=yes fi ;; + libproxy) + if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then + CFG_LIBPROXY="$VAL" + else + UNKNOWN_OPT=yes + fi + ;; qml-debug) if [ "$VAL" = "yes" ]; then CFG_QML_DEBUG="yes" @@ -2441,6 +2449,9 @@ Third Party Libraries: + -openssl ............ Enable run-time OpenSSL support. -openssl-linked ..... Enabled linked OpenSSL support. + -no-libproxy ....... Do not compile support for libproxy + + -libproxy .......... Use libproxy from the operating system. + -qt-pcre ............ Use the PCRE library bundled with Qt. + -system-pcre ........ Use the PCRE library from the operating system. @@ -4864,6 +4875,24 @@ if [ "$CFG_DBUS" = "linked" ]; then fi fi +# auto-detect libproxy support +if [ "$CFG_LIBPROXY" != "no" ]; then + if compileTest common/libproxy "libproxy"; then + CFG_LIBPROXY=yes + else + if [ "$CFG_LIBPROXY" = "auto" ]; then + CFG_LIBPROXY=no + elif [ "$CFG_CONFIGURE_EXIT_ON_ERROR" = "yes" ]; then + # CFG_LIBPROXY is "yes" here + echo "The libproxy support cannot be enabled because libproxy was not found." + echo " Turn on verbose messaging (-v) to $0 to see the final report." + echo " If you believe this message is in error you may use the continue" + echo " switch (-continue) to $0 to continue." + exit 101 + fi + fi +fi + # auto-detect Glib support if [ "$CFG_GLIB" != "no" ]; then if [ -n "$PKG_CONFIG" ]; then @@ -6039,6 +6068,7 @@ fi [ "$CFG_OPENSSL" = "yes" ] && QT_CONFIG="$QT_CONFIG openssl" [ "$CFG_OPENSSL" = "linked" ] && QT_CONFIG="$QT_CONFIG openssl-linked" [ "$CFG_SECURETRANSPORT" = "yes" ] && QT_CONFIG="$QT_CONFIG ssl securetransport" +[ "$CFG_LIBPROXY" = "yes" ] && QT_CONFIG="$QT_CONFIG libproxy" [ "$CFG_XCB" != "no" ] && QT_CONFIG="$QT_CONFIG xcb" [ "$CFG_XINPUT2" = "yes" ] && QT_CONFIG="$QT_CONFIG xinput2" [ "$CFG_SYSTEM_PROXIES" = "yes" ] && QT_CONFIG="$QT_CONFIG system-proxies" @@ -6430,6 +6460,7 @@ QMakeVar set sql-plugins "$SQL_PLUGINS" [ "$CFG_JPEG" != "yes" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_IMAGEFORMAT_JPEG" [ "$CFG_ZLIB" != "yes" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_ZLIB" [ "$CFG_DBUS" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_DBUS" +[ "$CFG_LIBPROXY" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_LIBPROXY" # X11/Unix/Mac only configs [ "$CFG_CUPS" = "no" ] && QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_CUPS" @@ -6878,6 +6909,7 @@ report_support " Networking:" report_support " getaddrinfo .........." "$CFG_GETADDRINFO" report_support " getifaddrs ..........." "$CFG_GETIFADDRS" report_support " IPv6 ifname .........." "$CFG_IPV6IFNAME" +report_support " libproxy.............." "$CFG_LIBPROXY" report_support " OpenSSL .............." "$CFG_OPENSSL" yes "loading libraries at run-time" linked "linked to the libraries" [ "$XPLATFORM_MAC" = "yes" ] && \ report_support " SecureTransport ......" "$CFG_SECURETRANSPORT" diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index 9b584be206..4f1527c8e9 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -54,7 +54,12 @@ mac { mac:!ios:SOURCES += kernel/qnetworkproxy_mac.cpp else:win32:SOURCES += kernel/qnetworkproxy_win.cpp -else:blackberry:SOURCES += kernel/qnetworkproxy_blackberry.cpp +else:blackberry { + SOURCES += kernel/qnetworkproxy_blackberry.cpp + LIBS_PRIVATE += -lbps +} +else:contains(QT_CONFIG, libproxy) { + SOURCES += kernel/qnetworkproxy_libproxy.cpp + LIBS += -lproxy +} else:SOURCES += kernel/qnetworkproxy_generic.cpp - -blackberry: LIBS_PRIVATE += -lbps diff --git a/src/network/kernel/qnetworkproxy_libproxy.cpp b/src/network/kernel/qnetworkproxy_libproxy.cpp new file mode 100644 index 0000000000..f0b91d6967 --- /dev/null +++ b/src/network/kernel/qnetworkproxy_libproxy.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnetworkproxy.h" + +#ifndef QT_NO_NETWORKPROXY + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QLibProxyWrapper +{ +public: + QLibProxyWrapper() + : factory(px_proxy_factory_new()) + { + if (!factory) + qWarning("libproxy initialization failed."); + } + + ~QLibProxyWrapper() + { + px_proxy_factory_free(factory); + } + + QList getProxies(const QUrl &url); + +private: + pxProxyFactory *factory; +}; + +Q_GLOBAL_STATIC(QLibProxyWrapper, libProxyWrapper); + +/* + Gets the list of proxies from libproxy, converted to QUrl list. + Thread safe, according to libproxy documentation. +*/ +QList QLibProxyWrapper::getProxies(const QUrl &url) +{ + QList ret; + + if (factory) { + char **proxies = px_proxy_factory_get_proxies(factory, url.toEncoded()); + if (proxies) { + for (int i = 0; proxies[i]; i++) { + ret.append(QUrl::fromEncoded(proxies[i])); + free(proxies[i]); + } + free(proxies); + } + } + + return ret; +} + +QList QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &query) +{ + QList proxyList; + + QUrl queryUrl; + QNetworkProxy::Capabilities requiredCapabilities(0); + switch (query.queryType()) { + //URL requests are directly supported by libproxy + case QNetworkProxyQuery::UrlRequest: + queryUrl = query.url(); + break; + // fake URLs to get libproxy to tell us the SOCKS proxy + case QNetworkProxyQuery::TcpSocket: + queryUrl.setScheme(QStringLiteral("tcp")); + queryUrl.setHost(query.peerHostName()); + queryUrl.setPort(query.peerPort()); + requiredCapabilities |= QNetworkProxy::TunnelingCapability; + break; + case QNetworkProxyQuery::UdpSocket: + queryUrl.setScheme(QStringLiteral("udp")); + queryUrl.setHost(query.peerHostName()); + queryUrl.setPort(query.peerPort()); + requiredCapabilities |= QNetworkProxy::UdpTunnelingCapability; + break; + default: + proxyList.append(QNetworkProxy(QNetworkProxy::NoProxy)); + return proxyList; + } + + QList rawProxies = libProxyWrapper()->getProxies(queryUrl); + + bool haveDirectConnection = false; + foreach (const QUrl& url, rawProxies) { + QNetworkProxy::ProxyType type; + if (url.scheme() == QStringLiteral("http")) { + type = QNetworkProxy::HttpProxy; + } else if (url.scheme() == QStringLiteral("socks") + || url.scheme() == QStringLiteral("socks5")) { + type = QNetworkProxy::Socks5Proxy; + } else if (url.scheme() == QStringLiteral("ftp")) { + type = QNetworkProxy::FtpCachingProxy; + } else if (url.scheme() == QStringLiteral("direct")) { + type = QNetworkProxy::NoProxy; + haveDirectConnection = true; + } else { + continue; //unsupported proxy type e.g. socks4 + } + + QNetworkProxy proxy(type, + url.host(QUrl::EncodeUnicode), + url.port(0), + url.userName(QUrl::FullyDecoded), + url.password(QUrl::FullyDecoded)); + + if (proxy.capabilities() & requiredCapabilities == requiredCapabilities) + proxyList.append(proxy); + } + + // fallback is direct connection + if (proxyList.isEmpty() || !haveDirectConnection) + proxyList.append(QNetworkProxy(QNetworkProxy::NoProxy)); + + return proxyList; +} + +QT_END_NAMESPACE + +#endif diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index dcbe52b1cf..7735f05989 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -269,6 +269,7 @@ Configure::Configure(int& argc, char** argv) dictionary[ "OPENVG" ] = "no"; dictionary[ "SSL" ] = "auto"; dictionary[ "OPENSSL" ] = "auto"; + dictionary[ "LIBPROXY" ] = "auto"; dictionary[ "DBUS" ] = "auto"; dictionary[ "STYLE_WINDOWS" ] = "yes"; @@ -859,6 +860,10 @@ void Configure::parseCmdLine() dictionary[ "OPENSSL" ] = "yes"; } else if (configCmdLine.at(i) == "-openssl-linked") { dictionary[ "OPENSSL" ] = "linked"; + } else if (configCmdLine.at(i) == "-no-libproxy") { + dictionary[ "LIBPROXY"] = "no"; + } else if (configCmdLine.at(i) == "-libproxy") { + dictionary[ "LIBPROXY" ] = "yes"; } else if (configCmdLine.at(i) == "-no-qdbus") { dictionary[ "DBUS" ] = "no"; } else if (configCmdLine.at(i) == "-qdbus") { @@ -1973,6 +1978,8 @@ bool Configure::displayHelp() desc("OPENSSL", "no", "-no-openssl", "Do not compile support for OpenSSL."); desc("OPENSSL", "yes", "-openssl", "Enable run-time OpenSSL support."); desc("OPENSSL", "linked","-openssl-linked", "Enable linked OpenSSL support.\n"); + desc("LIBPROXY", "no", "-no-libproxy", "Do not compile in libproxy support."); + desc("LIBPROXY", "yes", "-libproxy", "Compile in libproxy support (for cross compilation targets).\n"); desc("DBUS", "no", "-no-dbus", "Do not compile in D-Bus support."); desc("DBUS", "yes", "-dbus", "Compile in D-Bus support and load libdbus-1\ndynamically."); desc("DBUS", "linked", "-dbus-linked", "Compile in D-Bus support and link to libdbus-1.\n"); @@ -2234,6 +2241,8 @@ bool Configure::checkAvailability(const QString &part) available = tryCompileProject("common/avx2"); else if (part == "OPENSSL") available = findFile("openssl\\ssl.h"); + else if (part == "LIBPROXY") + available = dictionary.contains("XQMAKESPEC") && tryCompileProject("common/libproxy"); else if (part == "DBUS") available = findFile("dbus\\dbus.h"); else if (part == "CETEST") { @@ -2405,6 +2414,8 @@ void Configure::autoDetection() } if (dictionary["OPENSSL"] == "auto") dictionary["OPENSSL"] = checkAvailability("OPENSSL") ? "yes" : "no"; + if (dictionary["LIBPROXY"] == "auto") + dictionary["LIBPROXY"] = checkAvailability("LIBPROXY") ? "yes" : "no"; if (dictionary["DBUS"] == "auto") dictionary["DBUS"] = checkAvailability("DBUS") ? "yes" : "no"; if (dictionary["QML_DEBUG"] == "auto") @@ -2841,6 +2852,9 @@ void Configure::generateOutputVars() else if (dictionary[ "OPENSSL" ] == "linked") qtConfig += "openssl-linked"; + if (dictionary[ "LIBPROXY" ] == "yes") + qtConfig += "libproxy"; + if (dictionary[ "DBUS" ] == "yes") qtConfig += "dbus"; else if (dictionary[ "DBUS" ] == "linked") @@ -3695,6 +3709,7 @@ void Configure::displayConfig() sout << "OpenVG support.............." << dictionary[ "OPENVG" ] << endl; sout << "SSL support................." << dictionary[ "SSL" ] << endl; sout << "OpenSSL support............." << dictionary[ "OPENSSL" ] << endl; + sout << "libproxy support............" << dictionary[ "LIBPROXY" ] << endl; sout << "Qt D-Bus support............" << dictionary[ "DBUS" ] << endl; sout << "Qt Widgets module support..." << dictionary[ "WIDGETS" ] << endl; sout << "Qt GUI module support......." << dictionary[ "GUI" ] << endl; -- cgit v1.2.3