diff --git a/src/config.cpp b/src/config.cpp index ff7be96d4e..2cc96a6231 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -65,6 +65,7 @@ static const struct QCommandLineConfigEntry flags[] = { QCommandLine::Option, '\0', "proxy", "Sets the proxy server, e.g. '--proxy=http://proxy.company.com:8080'", QCommandLine::Optional }, { QCommandLine::Option, '\0', "proxy-auth", "Provides authentication information for the proxy, e.g. ''-proxy-auth=username:password'", QCommandLine::Optional }, { QCommandLine::Option, '\0', "proxy-type", "Specifies the proxy type, 'http' (default), 'none' (disable completely), or 'socks5'", QCommandLine::Optional }, + { QCommandLine::Option, '\0', "no-proxy", "Specifies the proxy exceptions, '127.0.0.1, localhost' (default)", QCommandLine::Optional }, { QCommandLine::Option, '\0', "script-encoding", "Sets the encoding used for the starting script, default is 'utf8'", QCommandLine::Optional }, { QCommandLine::Option, '\0', "script-language", "Sets the script language instead of detecting it: 'javascript'", QCommandLine::Optional }, { QCommandLine::Option, '\0', "web-security", "Enables web security, 'true' (default) or 'false'", QCommandLine::Optional }, @@ -348,6 +349,11 @@ int Config::proxyPort() const return m_proxyPort; } +QString Config::proxyExceptions() const +{ + return m_proxyExceptions; +} + QStringList Config::scriptArgs() const { return m_scriptArgs; @@ -554,6 +560,7 @@ void Config::resetToDefaults() m_proxyPort = 1080; m_proxyAuthUser.clear(); m_proxyAuthPass.clear(); + m_proxyExceptions.clear(); m_scriptArgs.clear(); m_scriptEncoding = "UTF-8"; m_scriptLanguage.clear(); @@ -616,6 +623,11 @@ void Config::setProxyPort(const int value) m_proxyPort = value; } +void Config::setProxyExceptions(const QString &value) +{ + m_proxyExceptions = value; +} + bool Config::helpFlag() const { return m_helpFlag; @@ -736,6 +748,10 @@ void Config::handleOption(const QString &option, const QVariant &value) setProxyAuth(value.toString()); } + if (option == "no-proxy") { + setProxyExceptions(value.toString()); + } + if (option == "script-encoding") { setScriptEncoding(value.toString()); } diff --git a/src/config.h b/src/config.h index d1240124b6..d06f8c8eec 100644 --- a/src/config.h +++ b/src/config.h @@ -51,6 +51,7 @@ class Config: public QObject Q_PROPERTY(QString proxyType READ proxyType WRITE setProxyType) Q_PROPERTY(QString proxy READ proxy WRITE setProxy) Q_PROPERTY(QString proxyAuth READ proxyAuth WRITE setProxyAuth) + Q_PROPERTY(QString noProxy READ proxyExceptions WRITE setProxyExceptions) Q_PROPERTY(QString scriptEncoding READ scriptEncoding WRITE setScriptEncoding) Q_PROPERTY(bool webSecurityEnabled READ webSecurityEnabled WRITE setWebSecurityEnabled) Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath) @@ -120,6 +121,9 @@ class Config: public QObject void setProxyAuthUser(const QString &value); void setProxyAuthPass(const QString &value); + QString proxyExceptions() const; + void setProxyExceptions(const QString &value); + QStringList scriptArgs() const; void setScriptArgs(const QStringList &value); @@ -213,6 +217,7 @@ public slots: int m_proxyPort; QString m_proxyAuthUser; QString m_proxyAuthPass; + QString m_proxyExceptions; QStringList m_scriptArgs; QString m_scriptEncoding; QString m_scriptLanguage; diff --git a/src/networkaccessmanager.cpp b/src/networkaccessmanager.cpp index 4b331f4029..ee58b529ec 100644 --- a/src/networkaccessmanager.cpp +++ b/src/networkaccessmanager.cpp @@ -43,6 +43,7 @@ #include "config.h" #include "cookiejar.h" #include "networkaccessmanager.h" +#include "networkproxyfactory.h" // 10 MB const qint64 MAX_REQUEST_POST_BODY_SIZE = 10 * 1000 * 1000; @@ -161,6 +162,8 @@ NetworkAccessManager::NetworkAccessManager(QObject *parent, const Config *config , m_networkDiskCache(0) , m_sslConfiguration(QSslConfiguration::defaultConfiguration()) { + NetworkProxyFactory* proxyFactory = new NetworkProxyFactory(); + if (config->diskCacheEnabled()) { m_networkDiskCache = new QNetworkDiskCache(this); m_networkDiskCache->setCacheDirectory(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); @@ -214,6 +217,11 @@ NetworkAccessManager::NetworkAccessManager(QObject *parent, const Config *config } } + if (proxyFactory->initializeFromEnvironment(config)) { + setProxyFactory(proxyFactory); + } + + connect(this, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), SLOT(provideAuthentication(QNetworkReply*,QAuthenticator*))); connect(this, SIGNAL(finished(QNetworkReply*)), SLOT(handleFinished(QNetworkReply*))); } diff --git a/src/networkproxyfactory.cpp b/src/networkproxyfactory.cpp new file mode 100644 index 0000000000..a64d66d9be --- /dev/null +++ b/src/networkproxyfactory.cpp @@ -0,0 +1,132 @@ +/* + This file is part of the PhantomJS project from Ofi Labs. + + Copyright (C) 2011 Ariya Hidayat + Copyright (C) 2011 Ivan De Marino + Copyright (C) 2014 Jef le Ponot + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include + +#include "networkproxyfactory.h" +#include "phantom.h" +#include "config.h" +#include "cookiejar.h" +#include "terminal.h" +NetworkProxyFactory::NetworkProxyFactory() +{ +} + +NetworkProxyFactory::~NetworkProxyFactory() +{ +} + +bool NetworkProxyFactory::initializeFromEnvironment(const Config *config) +{ + QString proxyType = config->proxyType(); + + if (proxyType == "none") + return false; + + if (config->proxyHost().isEmpty()) + return false; + + if (config->proxyExceptions().isEmpty()) + return false; + + QNetworkProxy::ProxyType networkProxyType; + if (proxyType == "socks5") + networkProxyType = QNetworkProxy::Socks5Proxy; + else + networkProxyType = QNetworkProxy::HttpProxy; + + if(!config->proxyAuthUser().isEmpty() && !config->proxyAuthPass().isEmpty()) + m_httpProxy << QNetworkProxy(networkProxyType, config->proxyHost(), config->proxyPort(), config->proxyAuthUser(), config->proxyAuthPass()); + else + m_httpProxy << QNetworkProxy(networkProxyType, config->proxyHost(), config->proxyPort()); + + QByteArray exceptions = config->proxyExceptions().toLocal8Bit(); + noProxyTokens = exceptions.split(','); + + return true; +} + + +bool NetworkProxyFactory::ignoreProxyFor(const QNetworkProxyQuery &query) +{ + foreach (const QByteArray rawToken, noProxyTokens) { + QByteArray token = rawToken.trimmed(); + QString peerHostName = query.peerHostName(); + + // Since we use suffix matching, "*" is our 'default' behaviour + if (token.startsWith("*")) + token = token.mid(1); + + // Harmonize trailing dot notation + if (token.endsWith('.') && !peerHostName.endsWith('.')) + token = token.left(token.length()-1); + + // We prepend a dot to both values, so that when we do a suffix match, + // we don't match "donotmatch.com" with "match.com" + if (!token.startsWith('.')) + token.prepend('.'); + + if (!peerHostName.startsWith('.')) + peerHostName.prepend('.'); + + if (peerHostName.endsWith(QString::fromLatin1(token))) + { + return true; + } + } + return false; +} + +QList NetworkProxyFactory::queryProxy(const QNetworkProxyQuery& query) +{ + QString protocol = query.protocolTag().toLower(); + /*bool localHost = false;*/ + QList noproxy; + noproxy << QNetworkProxy::NoProxy; + + //Terminal::instance()->cout(query.peerHostName()); + + if (!query.peerHostName().compare(QLatin1String("localhost"), Qt::CaseInsensitive) || !query.peerHostName().compare(QLatin1String("127.0.0.1"), Qt::CaseInsensitive)) + return noproxy; + if (ignoreProxyFor(query)) + return noproxy; + + return m_httpProxy; +/* + if (protocol == QLatin1String("https") && !localHost) + return m_httpsProxy; +*/ +} diff --git a/src/networkproxyfactory.h b/src/networkproxyfactory.h new file mode 100644 index 0000000000..5ebbaf0798 --- /dev/null +++ b/src/networkproxyfactory.h @@ -0,0 +1,77 @@ +/* + This file is part of the PhantomJS project from Ofi Labs. + + Copyright (C) 2011 Ariya Hidayat + Copyright (C) 2011 Ivan De Marino + Copyright (C) 2014 Jef le Ponot + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef NETWORKPROXYFACTORY_H +#define NETWORKPROXYFACTORY_H + +#include +#include +#include +#include +#include +#include +#include "config.h" + +class NetworkProxyFactory : public QObject, public QNetworkProxyFactory +{ + Q_OBJECT +public: + NetworkProxyFactory(); + ~NetworkProxyFactory(); + /* + void setHttpProxy(const QString &userName); + void setHttpsProxy(const QString &password); + void setFtpProxy(int maxAttempts); + void setSocksProxy(int resourceTimeout); + void setNoProxy(const QVariantMap &headers); + */ + bool initializeFromEnvironment(const Config *config); + + QList queryProxy(const QNetworkProxyQuery& query = QNetworkProxyQuery()); +protected: + +signals: + +private slots: + +private: + bool ignoreProxyFor(const QNetworkProxyQuery &query); + + QList m_httpProxy; + QList m_httpsProxy; + QList m_ftpProxy; + QList m_socksProxy; + + QList noProxyTokens; +}; + + +#endif //NETWORKPROXYFACTORY_H diff --git a/src/phantomjs.pro b/src/phantomjs.pro index a8eb9c1378..f578e0cb7d 100644 --- a/src/phantomjs.pro +++ b/src/phantomjs.pro @@ -25,6 +25,7 @@ HEADERS += \ consts.h \ utils.h \ networkaccessmanager.h \ + networkproxyfactory.h \ cookiejar.h \ filesystem.h \ system.h \ @@ -43,6 +44,7 @@ SOURCES += phantom.cpp \ main.cpp \ utils.cpp \ networkaccessmanager.cpp \ + networkproxyfactory.cpp \ cookiejar.cpp \ filesystem.cpp \ system.cpp \