Merge branch 'master' of git://scm.dev.nokia.troll.no/qt/qtbase-earth-staging

* 'master' of git://scm.dev.nokia.troll.no/qt/qtbase-earth-staging:
  Skip test on MacOS due to problems with corewlan plugin
  Fix QNetworkConfigurationManager usage outside main thread first
  Update QTBUG-17223 for Qt 4.8
  fix tst_qnetworkreply::httpProxyCommands autotest
  Send User-Agent from the network request in http proxy CONNECT command
  Add autotests for configuration dependent network proxies
  Fix QNetworkReplyImpl error handling
  Enable per network configuration proxy settings in QNetworkAccessManager
  Allow a network configuration to be included in a proxy query
  Fix error handling in write for socks socket engine
This commit is contained in:
Qt Continuous Integration System 2011-05-09 21:54:18 +10:00
commit e8aceff195
18 changed files with 476 additions and 45 deletions

View File

@ -520,6 +520,15 @@ bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket)
return false;
}
QHttpNetworkRequest QHttpNetworkConnectionPrivate::predictNextRequest()
{
if (!highPriorityQueue.isEmpty())
return highPriorityQueue.last().first;
if (!lowPriorityQueue.isEmpty())
return lowPriorityQueue.last().first;
return QHttpNetworkRequest();
}
// this is called from _q_startNextRequest and when a request has been sent down a socket from the channel
void QHttpNetworkConnectionPrivate::fillPipeline(QAbstractSocket *socket)
{

View File

@ -169,6 +169,7 @@ public:
void requeueRequest(const HttpMessagePair &pair); // e.g. after pipeline broke
bool dequeueRequest(QAbstractSocket *socket);
void prepareRequest(HttpMessagePair &request);
QHttpNetworkRequest predictNextRequest();
void fillPipeline(QAbstractSocket *socket);
bool fillPipeline(QList<HttpMessagePair> &queue, QHttpNetworkConnectionChannel &channel);

View File

@ -579,6 +579,17 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
connectHost = connection->d_func()->networkProxy.hostName();
connectPort = connection->d_func()->networkProxy.port();
}
if (socket->proxy().type() == QNetworkProxy::HttpProxy) {
// Make user-agent field available to HTTP proxy socket engine (QTBUG-17223)
QByteArray value;
// ensureConnection is called before any request has been assigned, but can also be called again if reconnecting
if (request.url().isEmpty())
value = connection->d_func()->predictNextRequest().headerField("user-agent");
else
value = request.headerField("user-agent");
if (!value.isEmpty())
socket->setProperty("_q_user-agent", value);
}
#endif
if (ssl) {
#ifndef QT_NO_OPENSSL

View File

@ -41,6 +41,7 @@
#include "qnetworkaccessbackend_p.h"
#include "qnetworkaccessmanager_p.h"
#include "qnetworkconfigmanager.h"
#include "qnetworkrequest.h"
#include "qnetworkreply.h"
#include "qnetworkreply_p.h"
@ -343,8 +344,6 @@ void QNetworkAccessBackend::sslErrors(const QList<QSslError> &errors)
#endif
}
#ifndef QT_NO_BEARERMANAGEMENT
/*!
Starts the backend. Returns true if the backend is started. Returns false if the backend
could not be started due to an unopened or roaming session. The caller should recall this
@ -352,31 +351,62 @@ void QNetworkAccessBackend::sslErrors(const QList<QSslError> &errors)
*/
bool QNetworkAccessBackend::start()
{
if (!manager->networkSession) {
open();
return true;
}
#ifndef QT_NO_BEARERMANAGEMENT
// For bearer, check if session start is required
if (manager->networkSession) {
// session required
if (manager->networkSession->isOpen() &&
manager->networkSession->state() == QNetworkSession::Connected) {
// Session is already open and ready to use.
// copy network session down to the backend
setProperty("_q_networksession", QVariant::fromValue(manager->networkSession));
} else {
// Session not ready, but can skip for loopback connections
// This is not ideal.
const QString host = reply->url.host();
if (host == QLatin1String("localhost") ||
QHostAddress(host) == QHostAddress::LocalHost ||
QHostAddress(host) == QHostAddress::LocalHostIPv6) {
// Don't need an open session for localhost access.
open();
return true;
}
// This is not ideal.
const QString host = reply->url.host();
if (manager->networkSession->isOpen() &&
manager->networkSession->state() == QNetworkSession::Connected) {
//copy network session down to the backend
setProperty("_q_networksession", QVariant::fromValue(manager->networkSession));
open();
return true;
if (host == QLatin1String("localhost") ||
QHostAddress(host) == QHostAddress::LocalHost ||
QHostAddress(host) == QHostAddress::LocalHostIPv6) {
// Don't need an open session for localhost access.
} else {
// need to wait for session to be opened
return false;
}
}
}
return false;
}
#endif
#ifndef QT_NO_NETWORKPROXY
#ifndef QT_NO_BEARERMANAGEMENT
// Get the proxy settings from the network session (in the case of service networks,
// the proxy settings change depending which AP was activated)
QNetworkSession *session = manager->networkSession.data();
QNetworkConfiguration config;
if (session) {
QNetworkConfigurationManager configManager;
// The active configuration tells us what IAP is in use
QVariant v = session->sessionProperty(QLatin1String("ActiveConfiguration"));
if (v.isValid())
config = configManager.configurationFromIdentifier(qvariant_cast<QString>(v));
// Fallback to using the configuration if no active configuration
if (!config.isValid())
config = session->configuration();
// or unspecified configuration if that is no good either
if (!config.isValid())
config = QNetworkConfiguration();
}
reply->proxyList = manager->queryProxy(QNetworkProxyQuery(config, url()));
#else // QT_NO_BEARERMANAGEMENT
// Without bearer management, the proxy depends only on the url
reply->proxyList = manager->queryProxy(QNetworkProxyQuery(url()));
#endif
#endif
// now start the request
open();
return true;
}
QT_END_NAMESPACE

View File

@ -1004,10 +1004,6 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
// third step: find a backend
priv->backend = d->findBackend(op, request);
#ifndef QT_NO_NETWORKPROXY
QList<QNetworkProxy> proxyList = d->queryProxy(QNetworkProxyQuery(request.url()));
priv->proxyList = proxyList;
#endif
if (priv->backend) {
priv->backend->setParent(reply);
priv->backend->reply = priv;

View File

@ -89,10 +89,10 @@ void QNetworkReplyImplPrivate::_q_startOperation()
return;
}
if (!backend->start()) {
#ifndef QT_NO_BEARERMANAGEMENT
if (!backend->start()) { // ### we should call that method even if bearer is not used
// backend failed to start because the session state is not Connected.
// QNetworkAccessManager will call reply->backend->start() again for us when the session
// QNetworkAccessManager will call _q_startOperation again for us when the session
// state changes.
state = WaitingForSession;
@ -108,11 +108,20 @@ void QNetworkReplyImplPrivate::_q_startOperation()
session->open();
} else {
qWarning("Backend is waiting for QNetworkSession to connect, but there is none!");
state = Working;
error(QNetworkReplyImpl::UnknownNetworkError,
QCoreApplication::translate("QNetworkReply", "Network session error."));
finished();
}
#else
qWarning("Backend start failed");
state = Working;
error(QNetworkReplyImpl::UnknownNetworkError,
QCoreApplication::translate("QNetworkReply", "backend start error."));
finished();
#endif
return;
}
#endif
if (backend && backend->isSynchronous()) {
state = Finished;

View File

@ -385,8 +385,6 @@ void QNetworkConfigurationManagerPrivate::updateConfigurations()
this, SLOT(configurationRemoved(QNetworkConfigurationPrivatePointer)));
connect(engine, SIGNAL(configurationChanged(QNetworkConfigurationPrivatePointer)),
this, SLOT(configurationChanged(QNetworkConfigurationPrivatePointer)));
QMetaObject::invokeMethod(engine, "initialize");
}
}
@ -410,8 +408,19 @@ void QNetworkConfigurationManagerPrivate::updateConfigurations()
startPolling();
}
if (firstUpdate)
if (firstUpdate) {
firstUpdate = false;
QList<QBearerEngine*> enginesToInitialize = sessionEngines; //shallow copy the list in case it is modified when we unlock mutex
Qt::ConnectionType connectionType;
if (QCoreApplicationPrivate::mainThread() == QThread::currentThread())
connectionType = Qt::DirectConnection;
else
connectionType = Qt::BlockingQueuedConnection;
locker.unlock();
foreach (QBearerEngine* engine, enginesToInitialize) {
QMetaObject::invokeMethod(engine, "initialize", connectionType);
}
}
}
void QNetworkConfigurationManagerPrivate::performAsyncConfigurationUpdate()

View File

@ -228,6 +228,10 @@
#include "qmutex.h"
#include "qurl.h"
#ifndef QT_NO_BEARERMANAGEMENT
#include <QtNetwork/QNetworkConfiguration>
#endif
QT_BEGIN_NAMESPACE
class QSocks5SocketEngineHandler;
@ -716,6 +720,9 @@ public:
QUrl remote;
int localPort;
QNetworkProxyQuery::QueryType type;
#ifndef QT_NO_BEARERMANAGEMENT
QNetworkConfiguration config;
#endif
};
template<> void QSharedDataPointer<QNetworkProxyQueryPrivate>::detach()
@ -777,6 +784,11 @@ template<> void QSharedDataPointer<QNetworkProxyQueryPrivate>::detach()
like choosing an caching HTTP proxy for HTTP-based connections,
but a more powerful SOCKSv5 proxy for all others.
The network configuration specifies which configuration to use,
when bearer management is used. For example on a mobile phone
the proxy settings are likely to be different for the cellular
network vs WLAN.
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.
@ -902,6 +914,68 @@ QNetworkProxyQuery::QNetworkProxyQuery(quint16 bindPort, const QString &protocol
d->type = queryType;
}
#ifndef QT_NO_BEARERMANAGEMENT
/*!
Constructs a QNetworkProxyQuery with the URL \a requestUrl and
sets the query type to \a queryType. The specified \a networkConfiguration
is used to resolve the proxy settings.
\sa protocolTag(), peerHostName(), peerPort(), networkConfiguration()
*/
QNetworkProxyQuery::QNetworkProxyQuery(const QNetworkConfiguration &networkConfiguration,
const QUrl &requestUrl, QueryType queryType)
{
d->config = networkConfiguration;
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. The specified \a networkConfiguration
is used to resolve the proxy settings.
\sa networkConfiguration()
*/
QNetworkProxyQuery::QNetworkProxyQuery(const QNetworkConfiguration &networkConfiguration,
const QString &hostname, int port,
const QString &protocolTag,
QueryType queryType)
{
d->config = networkConfiguration;
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. The specified \a networkConfiguration
is used to resolve the proxy settings.
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(), networkConfiguration()
*/
QNetworkProxyQuery::QNetworkProxyQuery(const QNetworkConfiguration &networkConfiguration,
quint16 bindPort, const QString &protocolTag,
QueryType queryType)
{
d->config = networkConfiguration;
d->remote.setScheme(protocolTag);
d->localPort = bindPort;
d->type = queryType;
}
#endif
/*!
Constructs a QNetworkProxyQuery object that is a copy of \a other.
*/
@ -1116,6 +1190,30 @@ void QNetworkProxyQuery::setUrl(const QUrl &url)
d->remote = url;
}
#ifndef QT_NO_BEARERMANAGEMENT
QNetworkConfiguration QNetworkProxyQuery::networkConfiguration() const
{
return d ? d->config : QNetworkConfiguration();
}
/*!
Sets the network configuration component of this QNetworkProxyQuery
object to be \a networkConfiguration. The network configuration can
be used to return different proxy settings based on the network in
use, for example WLAN vs cellular networks on a mobile phone.
In the case of "user choice" or "service network" configurations,
you should first start the QNetworkSession and obtain the active
configuration from its properties.
\sa networkConfiguration
*/
void QNetworkProxyQuery::setNetworkConfiguration(const QNetworkConfiguration &networkConfiguration)
{
d->config = networkConfiguration;
}
#endif
/*!
\class QNetworkProxyFactory
\brief The QNetworkProxyFactory class provides fine-grained proxy selection.

View File

@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Network)
class QUrl;
class QNetworkConfiguration;
class QNetworkProxyQueryPrivate;
class Q_NETWORK_EXPORT QNetworkProxyQuery
@ -73,6 +74,16 @@ public:
QNetworkProxyQuery(quint16 bindPort, const QString &protocolTag = QString(),
QueryType queryType = TcpServer);
QNetworkProxyQuery(const QNetworkProxyQuery &other);
#ifndef QT_NO_BEARERMANAGEMENT
QNetworkProxyQuery(const QNetworkConfiguration &networkConfiguration,
const QUrl &requestUrl, QueryType queryType = UrlRequest);
QNetworkProxyQuery(const QNetworkConfiguration &networkConfiguration,
const QString &hostname, int port, const QString &protocolTag = QString(),
QueryType queryType = TcpSocket);
QNetworkProxyQuery(const QNetworkConfiguration &networkConfiguration,
quint16 bindPort, const QString &protocolTag = QString(),
QueryType queryType = TcpServer);
#endif
~QNetworkProxyQuery();
QNetworkProxyQuery &operator=(const QNetworkProxyQuery &other);
bool operator==(const QNetworkProxyQuery &other) const;
@ -97,6 +108,11 @@ public:
QUrl url() const;
void setUrl(const QUrl &url);
#ifndef QT_NO_BEARERMANAGEMENT
QNetworkConfiguration networkConfiguration() const;
void setNetworkConfiguration(const QNetworkConfiguration &networkConfiguration);
#endif
private:
QSharedDataPointer<QNetworkProxyQueryPrivate> d;
};

View File

@ -58,6 +58,7 @@
#include <commsdattypeinfov1_1.h> // CCDIAPRecord, CCDProxiesRecord
#include <commsdattypesv1_1.h> // KCDTIdIAPRecord, KCDTIdProxiesRecord
#include <QtNetwork/QNetworkConfigurationManager>
#include <QtNetwork/QNetworkConfiguration>
#include <QFlags>
using namespace CommsDat;
@ -88,7 +89,7 @@ class SymbianProxyQuery
{
public:
static QNetworkConfiguration findCurrentConfiguration(QNetworkConfigurationManager& configurationManager);
static SymbianIapId getIapId(QNetworkConfigurationManager& configurationManager);
static SymbianIapId getIapId(QNetworkConfigurationManager &configurationManager, const QNetworkProxyQuery &query);
static CCDIAPRecord *getIapRecordLC(TUint32 aIAPId, CMDBSession &aDb);
static CMDBRecordSet<CCDProxiesRecord> *prepareQueryLC(TUint32 serviceId, TDesC& serviceType);
static QList<QNetworkProxy> proxyQueryL(TUint32 aIAPId, const QNetworkProxyQuery &query);
@ -137,11 +138,15 @@ QNetworkConfiguration SymbianProxyQuery::findCurrentConfiguration(QNetworkConfig
return currentConfig;
}
SymbianIapId SymbianProxyQuery::getIapId(QNetworkConfigurationManager& configurationManager)
SymbianIapId SymbianProxyQuery::getIapId(QNetworkConfigurationManager& configurationManager, const QNetworkProxyQuery &query)
{
SymbianIapId iapId;
QNetworkConfiguration currentConfig = findCurrentConfiguration(configurationManager);
QNetworkConfiguration currentConfig = query.networkConfiguration();
if (!currentConfig.isValid()) {
//If config is not specified, then try to find out an active or default one
currentConfig = findCurrentConfiguration(configurationManager);
}
if (currentConfig.isValid()) {
// Note: the following code assumes that the identifier is in format
// I_xxxx where xxxx is the identifier of IAP. This is meant as a
@ -249,7 +254,7 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
SymbianIapId iapId;
TInt error;
QNetworkConfigurationManager manager;
iapId = SymbianProxyQuery::getIapId(manager);
iapId = SymbianProxyQuery::getIapId(manager, query);
if (iapId.isValid()) {
TRAP(error, proxies = SymbianProxyQuery::proxyQueryL(iapId.iapId(), query))
if (error != KErrNone) {

View File

@ -556,6 +556,10 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc
q->setErrorString(QAbstractSocket::tr("Operation on socket is not supported"));
return false;
}
#ifndef QT_NO_NETWORKPROXY
//copy user agent to socket engine (if it has been set)
socketEngine->setProperty("_q_user-agent", q->property("_q_user-agent"));
#endif
if (!socketEngine->initialize(q->socketType(), protocol)) {
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::initSocketLayer(%s, %s) failed (%s)",

View File

@ -501,7 +501,13 @@ void QHttpSocketEngine::slotSocketConnected()
data += path;
data += " HTTP/1.1\r\n";
data += "Proxy-Connection: keep-alive\r\n"
"User-Agent: Mozilla/5.0\r\n"
"User-Agent: ";
QVariant v = property("_q_user-agent");
if (v.isValid())
data += v.toByteArray();
else
data += "Mozilla/5.0";
data += "\r\n"
"Host: " + peerAddress + "\r\n";
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
//qDebug() << "slotSocketConnected: priv=" << priv << (priv ? (int)priv->method : -1);

View File

@ -1540,8 +1540,13 @@ qint64 QSocks5SocketEngine::write(const char *data, qint64 len)
// ### Handle this error.
}
d->data->controlSocket->write(sealedBuf);
qint64 written = d->data->controlSocket->write(sealedBuf);
if (written <= 0) {
QSOCKS5_Q_DEBUG << "native write returned" << written;
return written;
}
d->data->controlSocket->waitForBytesWritten(0);
//NB: returning len rather than written for the OK case, because the "sealing" may increase the length
return len;
#ifndef QT_NO_UDPSOCKET
} else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode) {

View File

@ -1736,6 +1736,8 @@ void QSslSocket::connectToHostImplementation(const QString &hostName, quint16 po
}
#ifndef QT_NO_NETWORKPROXY
d->plainSocket->setProxy(proxy());
//copy user agent down to the plain socket (if it has been set)
d->plainSocket->setProperty("_q_user-agent", property("_q_user-agent"));
#endif
QIODevice::open(openMode);
d->plainSocket->connectToHost(hostName, port, openMode);

View File

@ -62,6 +62,7 @@ public slots:
void cleanup();
private slots:
void usedInThread(); // this test must be first, or it will falsely pass
void allConfigurations();
void defaultConfiguration();
void configurationFromIdentifier();
@ -329,6 +330,47 @@ void tst_QNetworkConfigurationManager::configurationFromIdentifier()
QVERIFY(!invalid.isValid());
}
class QNCMTestThread : public QThread
{
protected:
virtual void run()
{
QNetworkConfigurationManager manager;
preScanConfigs = manager.allConfigurations();
QSignalSpy spy(&manager, SIGNAL(updateCompleted()));
manager.updateConfigurations(); //initiate scans
QTRY_VERIFY(spy.count() == 1); //wait for scan to complete
configs = manager.allConfigurations();
}
public:
QList<QNetworkConfiguration> configs;
QList<QNetworkConfiguration> preScanConfigs;
};
// regression test for QTBUG-18795
void tst_QNetworkConfigurationManager::usedInThread()
{
#if defined Q_OS_MAC && !defined (QT_NO_COREWLAN)
QSKIP("QTBUG-19070 Mac CoreWlan plugin is broken", SkipAll);
#else
QNCMTestThread thread;
connect(&thread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
thread.start();
QTestEventLoop::instance().enterLoop(100); //QTRY_VERIFY could take ~90 seconds to time out in the thread
QVERIFY(thread.isFinished());
qDebug() << "prescan:" << thread.preScanConfigs.count();
qDebug() << "postscan:" << thread.configs.count();
QNetworkConfigurationManager manager;
QList<QNetworkConfiguration> preScanConfigs = manager.allConfigurations();
QSignalSpy spy(&manager, SIGNAL(updateCompleted()));
manager.updateConfigurations(); //initiate scans
QTRY_VERIFY(spy.count() == 1); //wait for scan to complete
QList<QNetworkConfiguration> configs = manager.allConfigurations();
QCOMPARE(thread.configs, configs);
QCOMPARE(thread.preScanConfigs, preScanConfigs);
#endif
}
QTEST_MAIN(tst_QNetworkConfigurationManager)
#include "tst_qnetworkconfigurationmanager.moc"

View File

@ -7,5 +7,5 @@ QT = core network
SOURCES += tst_qnetworkproxyfactory.cpp
symbian: TARGET.CAPABILITY = NetworkServices
symbian: TARGET.CAPABILITY = NetworkServices ReadUserData

View File

@ -41,20 +41,64 @@
#include <QtTest/QTest>
#include <QtTest/QTestEventLoop>
#include <qcoreapplication.h>
#include <qdebug.h>
#include <qnetworkproxy.h>
#include <QNetworkConfiguration>
#include <QNetworkConfigurationManager>
#include <QNetworkSession>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QList>
Q_DECLARE_METATYPE(QNetworkConfiguration);
Q_DECLARE_METATYPE(QList<QNetworkProxy>);
#include <QThread>
class tst_QNetworkProxyFactory : public QObject {
Q_OBJECT
public:
tst_QNetworkProxyFactory();
class QDebugProxyFactory : public QNetworkProxyFactory
{
public:
virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query = QNetworkProxyQuery())
{
returnedList = QNetworkProxyFactory::systemProxyForQuery(query);
requestCounter++;
return returnedList;
}
QList<QNetworkProxy> returnedList;
int requestCounter;
};
private slots:
void systemProxyForQueryCalledFromThread();
void systemProxyForQuery() const;
#ifndef QT_NO_BEARERMANAGEMENT
void fromConfigurations();
void inNetworkAccessManager_data();
void inNetworkAccessManager();
#endif
private:
QString formatProxyName(const QNetworkProxy & proxy) const;
QDebugProxyFactory *factory;
};
tst_QNetworkProxyFactory::tst_QNetworkProxyFactory()
{
factory = new QDebugProxyFactory;
QNetworkProxyFactory::setApplicationProxyFactory(factory);
}
QString tst_QNetworkProxyFactory::formatProxyName(const QNetworkProxy & proxy) const
{
QString proxyName;
@ -96,5 +140,136 @@ void tst_QNetworkProxyFactory::systemProxyForQuery() const
QFAIL("One or more system proxy lookup failures occurred.");
}
#ifndef QT_NO_BEARERMANAGEMENT
//Purpose of this test is just to check systemProxyForQuery doesn't hang or crash
//with any given configuration including no configuration.
//We can't test it returns the right proxies without implementing the native proxy code
//again here, which would be testing our implementation against itself.
//Therefore it's just testing that something valid is returned (at least a NoProxy entry)
void tst_QNetworkProxyFactory::fromConfigurations()
{
QNetworkConfigurationManager manager;
QList<QNetworkProxy> proxies;
QUrl url(QLatin1String("http://qt.nokia.com"));
//get from known configurations
foreach (QNetworkConfiguration config, manager.allConfigurations()) {
QNetworkProxyQuery query(config, url, QNetworkProxyQuery::UrlRequest);
proxies = QNetworkProxyFactory::systemProxyForQuery(query);
QVERIFY(!proxies.isEmpty());
foreach (QNetworkProxy proxy, proxies) {
qDebug() << config.name() << " - " << config.identifier() << " - " << formatProxyName(proxy);
}
}
//get from default configuration
QNetworkProxyQuery defaultquery(url, QNetworkProxyQuery::UrlRequest);
proxies = QNetworkProxyFactory::systemProxyForQuery(defaultquery);
QVERIFY(!proxies.isEmpty());
foreach (QNetworkProxy proxy, proxies) {
qDebug() << "default - " << formatProxyName(proxy);
}
//get from active configuration
QNetworkSession session(manager.defaultConfiguration());
session.open();
QVERIFY(session.waitForOpened(30000));
proxies = QNetworkProxyFactory::systemProxyForQuery(defaultquery);
QVERIFY(!proxies.isEmpty());
foreach (QNetworkProxy proxy, proxies) {
qDebug() << "active - " << formatProxyName(proxy);
}
//get from known configurations while there is one active
foreach (QNetworkConfiguration config, manager.allConfigurations()) {
QNetworkProxyQuery query(config, url, QNetworkProxyQuery::UrlRequest);
proxies = QNetworkProxyFactory::systemProxyForQuery(query);
QVERIFY(!proxies.isEmpty());
foreach (QNetworkProxy proxy, proxies) {
qDebug() << config.name() << " - " << config.identifier() << " - " << formatProxyName(proxy);
}
}
}
void tst_QNetworkProxyFactory::inNetworkAccessManager_data()
{
QTest::addColumn<QNetworkConfiguration>("config");
QTest::addColumn<QList<QNetworkProxy> >("proxies");
QNetworkConfigurationManager manager;
//get from known configurations
foreach (QNetworkConfiguration config, manager.allConfigurations()) {
QNetworkProxyQuery query(config, QUrl(QString("http://qt.nokia.com")), QNetworkProxyQuery::UrlRequest);
QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery(query);
QTest::newRow(config.name().toUtf8()) << config << proxies;
}
}
//Purpose of this test is to check that QNetworkAccessManager uses the proxy from the configuration it
//has been given. Needs two or more working configurations to be a good test.
void tst_QNetworkProxyFactory::inNetworkAccessManager()
{
QFETCH(QNetworkConfiguration, config);
QFETCH(QList<QNetworkProxy>, proxies);
int count = factory->requestCounter;
QNetworkAccessManager manager;
manager.setConfiguration(config);
//using an internet server, because cellular APs won't have a route to the test server.
QNetworkRequest req(QUrl(QString("http://qt.nokia.com")));
QNetworkReply *reply = manager.get(req);
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
QTestEventLoop::instance().enterLoop(30);
delete reply;
if (count == factory->requestCounter) {
//RND phones are preconfigured with several test access points which won't work without a matching SIM
//If the network fails to start, QNAM won't ask the factory for proxies so we can't test.
QSKIP("network configuration didn't start", SkipSingle);
}
qDebug() << "testing network configuration for" << config.name();
foreach (QNetworkProxy proxy, factory->returnedList) {
qDebug() << formatProxyName(proxy);
}
qDebug() << " <vs> ";
foreach (QNetworkProxy proxy, proxies) {
qDebug() << formatProxyName(proxy);
}
if (config.type() != QNetworkConfiguration::InternetAccessPoint)
QEXPECT_FAIL("","QNetworkProxyFactory::systemProxyForQuery doesn't work for service networks yet", Continue);
QCOMPARE(factory->returnedList, proxies);
}
#endif //QT_NO_BEARERMANAGEMENT
class QSPFQThread : public QThread
{
protected:
virtual void run()
{
proxies = QNetworkProxyFactory::systemProxyForQuery(query);
}
public:
QNetworkProxyQuery query;
QList<QNetworkProxy> proxies;
};
//regression test for QTBUG-18799
void tst_QNetworkProxyFactory::systemProxyForQueryCalledFromThread()
{
QUrl url(QLatin1String("http://qt.nokia.com"));
QNetworkProxyQuery query(url);
QSPFQThread thread;
thread.query = query;
connect(&thread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
thread.start();
QTestEventLoop::instance().enterLoop(5);
QVERIFY(thread.isFinished());
QCOMPARE(thread.proxies, QNetworkProxyFactory::systemProxyForQuery(query));
}
QTEST_MAIN(tst_QNetworkProxyFactory)
#include "tst_qnetworkproxyfactory.moc"

View File

@ -4970,17 +4970,24 @@ void tst_QNetworkReply::httpProxyCommands()
QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort());
manager.setProxy(proxy);
QNetworkReplyPtr reply = manager.get(QNetworkRequest(url));
manager.setProxy(QNetworkProxy());
QNetworkRequest request(url);
request.setRawHeader("User-Agent", "QNetworkReplyAutoTest/1.0");
QNetworkReplyPtr reply = manager.get(request);
//clearing the proxy here causes the test to fail.
//the proxy isn't used until after the bearer has been started
//which is correct in general, because system proxy isn't known until that time.
//removing this line is safe, as the proxy is also reset by the cleanup() function
//manager.setProxy(QNetworkProxy());
// wait for the finished signal
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
QTestEventLoop::instance().enterLoop(1);
QTestEventLoop::instance().enterLoop(15);
QVERIFY(!QTestEventLoop::instance().timeout());
//qDebug() << reply->error() << reply->errorString();
//qDebug() << proxyServer.receivedData;
// we don't really care if the request succeeded
// especially since it won't succeed in the HTTPS case
@ -4988,6 +4995,12 @@ void tst_QNetworkReply::httpProxyCommands()
QString receivedHeader = proxyServer.receivedData.left(expectedCommand.length());
QCOMPARE(receivedHeader, expectedCommand);
//QTBUG-17223 - make sure the user agent from the request is sent to proxy server even for CONNECT
int uapos = proxyServer.receivedData.indexOf("User-Agent");
int uaend = proxyServer.receivedData.indexOf("\r\n", uapos);
QByteArray uaheader = proxyServer.receivedData.mid(uapos, uaend - uapos);
QCOMPARE(uaheader, QByteArray("User-Agent: QNetworkReplyAutoTest/1.0"));
}
class ProxyChangeHelper : public QObject {