mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-05-03 23:57:19 +08:00
1083 lines
40 KiB
C++
1083 lines
40 KiB
C++
// Copyright (C) 2016 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
#include <QTest>
|
|
#include <QtNetwork/QtNetwork>
|
|
#include <QtCore/QDateTime>
|
|
#include <QtCore/QElapsedTimer>
|
|
#include <QtCore/QTextStream>
|
|
#include <QtCore/QRandomGenerator>
|
|
#include <QtCore/QStandardPaths>
|
|
#include <QtCore/private/qiodevice_p.h>
|
|
|
|
#include "../../network-settings.h"
|
|
|
|
#ifndef QT_NO_OPENSSL
|
|
QT_BEGIN_NAMESPACE
|
|
void qt_ForceTlsSecurityLevel();
|
|
QT_END_NAMESPACE
|
|
#endif
|
|
|
|
class tst_NetworkSelfTest: public QObject
|
|
{
|
|
Q_OBJECT
|
|
// This is either old server's address, or the new http
|
|
// server's address (different from ftp, for example):
|
|
QHostAddress cachedIpAddress;
|
|
// This is only for the new docker test server:
|
|
QHostAddress ftpServerIpAddress;
|
|
public:
|
|
tst_NetworkSelfTest();
|
|
virtual ~tst_NetworkSelfTest();
|
|
|
|
QHostAddress serverIpAddress();
|
|
|
|
private slots:
|
|
void initTestCase();
|
|
void hostTest();
|
|
void dnsResolution_data();
|
|
void dnsResolution();
|
|
void serverReachability();
|
|
void remotePortsOpen_data();
|
|
void remotePortsOpen();
|
|
|
|
// specific protocol tests
|
|
void ftpServer();
|
|
void ftpProxyServer();
|
|
void imapServer();
|
|
void httpServer();
|
|
void httpServerFiles_data();
|
|
void httpServerFiles();
|
|
void httpServerCGI_data();
|
|
void httpServerCGI();
|
|
#ifndef QT_NO_SSL
|
|
void httpsServer();
|
|
#endif
|
|
void httpProxy();
|
|
void httpProxyBasicAuth();
|
|
void httpProxyNtlmAuth();
|
|
void socks5Proxy();
|
|
void socks5ProxyAuth();
|
|
void smbServer();
|
|
|
|
// ssl supported test
|
|
void supportsSsl();
|
|
};
|
|
|
|
class Chat
|
|
{
|
|
public:
|
|
enum Type {
|
|
Reconnect,
|
|
Send,
|
|
Expect,
|
|
SkipBytes,
|
|
DiscardUntil,
|
|
DiscardUntilDisconnect,
|
|
Disconnect,
|
|
RemoteDisconnect,
|
|
StartEncryption
|
|
};
|
|
Chat(Type t, const QByteArray &d)
|
|
: data(d), type(t)
|
|
{
|
|
}
|
|
Chat(Type t, int val = 0)
|
|
: value(val), type(t)
|
|
{
|
|
}
|
|
|
|
static inline Chat send(const QByteArray &data)
|
|
{ return Chat(Send, data); }
|
|
static inline Chat expect(const QByteArray &data)
|
|
{ return Chat(Expect, data); }
|
|
static inline Chat discardUntil(const QByteArray &data)
|
|
{ return Chat(DiscardUntil, data); }
|
|
static inline Chat skipBytes(int count)
|
|
{ return Chat(SkipBytes, count); }
|
|
|
|
QByteArray data;
|
|
int value;
|
|
Type type;
|
|
};
|
|
|
|
static QString prettyByteArray(const QByteArray &array)
|
|
{
|
|
// any control chars?
|
|
QString result;
|
|
result.reserve(array.size() + array.size() / 3);
|
|
for (int i = 0; i < array.size(); ++i) {
|
|
char c = array.at(i);
|
|
switch (c) {
|
|
case '\n':
|
|
result += "\\n";
|
|
continue;
|
|
case '\r':
|
|
result += "\\r";
|
|
continue;
|
|
case '\t':
|
|
result += "\\t";
|
|
continue;
|
|
case '"':
|
|
result += "\\\"";
|
|
continue;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (c < 0x20 || uchar(c) >= 0x7f) {
|
|
result += '\\';
|
|
result += QString::number(uchar(c), 8);
|
|
} else {
|
|
result += c;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
enum { defaultReadTimeoutMS = 4000 };
|
|
|
|
static bool doSocketRead(QTcpSocket *socket, int minBytesAvailable, int timeout = defaultReadTimeoutMS)
|
|
{
|
|
QElapsedTimer timer;
|
|
timer.start();
|
|
int t = timeout;
|
|
forever {
|
|
if (socket->bytesAvailable() >= minBytesAvailable)
|
|
return true;
|
|
if (socket->state() == QAbstractSocket::UnconnectedState)
|
|
return false;
|
|
if (!socket->waitForReadyRead(t))
|
|
return false;
|
|
t = qt_subtract_from_timeout(timeout, timer.elapsed());
|
|
if (t == 0)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static QByteArray msgDoSocketReadFailed(const QString &host, quint16 port,
|
|
int step, int minBytesAvailable)
|
|
{
|
|
return "Failed to receive "
|
|
+ QByteArray::number(minBytesAvailable) + " bytes from "
|
|
+ host.toLatin1() + ':' + QByteArray::number(port)
|
|
+ " in step " + QByteArray::number(step) + ": timeout";
|
|
}
|
|
|
|
static bool doSocketFlush(QTcpSocket *socket, int timeout = 4000)
|
|
{
|
|
#ifndef QT_NO_SSL
|
|
QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket);
|
|
#endif
|
|
QElapsedTimer timer;
|
|
timer.start();
|
|
int t = timeout;
|
|
forever {
|
|
if (socket->bytesToWrite() == 0
|
|
#ifndef QT_NO_SSL
|
|
&& sslSocket->encryptedBytesToWrite() == 0
|
|
#endif
|
|
)
|
|
return true;
|
|
if (socket->state() == QAbstractSocket::UnconnectedState)
|
|
return false;
|
|
if (!socket->waitForBytesWritten(t))
|
|
return false;
|
|
t = qt_subtract_from_timeout(timeout, timer.elapsed());
|
|
if (t == 0)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static void netChat(int port, const QList<Chat> &chat)
|
|
{
|
|
#ifndef QT_NO_SSL
|
|
QSslSocket socket;
|
|
#else
|
|
QTcpSocket socket;
|
|
#endif
|
|
const auto serverName = QtNetworkSettings::hostWithServiceOnPort(port);
|
|
socket.connectToHost(serverName, port);
|
|
qDebug() << 0 << "Connecting to server on port" << port;
|
|
QVERIFY2(socket.waitForConnected(10000),
|
|
QString("Failed to connect to server in step 0: %1").arg(socket.errorString()).toLocal8Bit());
|
|
|
|
// now start the chat
|
|
QList<Chat>::ConstIterator it = chat.constBegin();
|
|
for (int i = 1; it != chat.constEnd(); ++it, ++i) {
|
|
switch (it->type) {
|
|
case Chat::Expect: {
|
|
qDebug() << i << "Expecting" << prettyByteArray(it->data);
|
|
if (!doSocketRead(&socket, it->data.size(), 3 * defaultReadTimeoutMS))
|
|
QFAIL(msgDoSocketReadFailed(serverName, port, i, it->data.size()));
|
|
|
|
// pop that many bytes off the socket
|
|
QByteArray received = socket.read(it->data.size());
|
|
|
|
// is it what we expected?
|
|
QVERIFY2(received == it->data,
|
|
QString("Did not receive expected data in step %1: data received was:\n%2")
|
|
.arg(i).arg(prettyByteArray(received)).toLocal8Bit());
|
|
|
|
break;
|
|
}
|
|
|
|
case Chat::DiscardUntil:
|
|
qDebug() << i << "Discarding until" << prettyByteArray(it->data);
|
|
while (true) {
|
|
// scan the buffer until we have our string
|
|
if (!doSocketRead(&socket, it->data.size()))
|
|
QFAIL(msgDoSocketReadFailed(serverName, port, i, it->data.size()));
|
|
|
|
QByteArray buffer;
|
|
buffer.resize(socket.bytesAvailable());
|
|
socket.peek(buffer.data(), socket.bytesAvailable());
|
|
|
|
int pos = buffer.indexOf(it->data);
|
|
if (pos == -1) {
|
|
// data not found, keep trying
|
|
continue;
|
|
}
|
|
|
|
buffer = socket.read(pos + it->data.size());
|
|
qDebug() << i << "Discarded" << prettyByteArray(buffer);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Chat::SkipBytes: {
|
|
qDebug() << i << "Skipping" << it->value << "bytes";
|
|
if (!doSocketRead(&socket, it->value))
|
|
QFAIL(msgDoSocketReadFailed(serverName, port, i, it->value));
|
|
|
|
// now discard the bytes
|
|
QByteArray buffer = socket.read(it->value);
|
|
qDebug() << i << "Skipped" << prettyByteArray(buffer);
|
|
break;
|
|
}
|
|
|
|
case Chat::Send: {
|
|
qDebug() << i << "Sending" << prettyByteArray(it->data);
|
|
socket.write(it->data);
|
|
if (!doSocketFlush(&socket)) {
|
|
QVERIFY2(socket.state() == QAbstractSocket::ConnectedState,
|
|
QString("Socket disconnected while sending data in step %1").arg(i).toLocal8Bit());
|
|
QFAIL(QString("Failed to send data in step %1: timeout").arg(i).toLocal8Bit());
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Chat::Disconnect:
|
|
qDebug() << i << "Disconnecting from host";
|
|
socket.disconnectFromHost();
|
|
|
|
// is this the last command?
|
|
if (it + 1 != chat.constEnd())
|
|
break;
|
|
|
|
Q_FALLTHROUGH();
|
|
case Chat::RemoteDisconnect:
|
|
case Chat::DiscardUntilDisconnect:
|
|
qDebug() << i << "Waiting for remote disconnect";
|
|
if (socket.state() != QAbstractSocket::UnconnectedState)
|
|
socket.waitForDisconnected(10000);
|
|
QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState,
|
|
QString("Socket did not disconnect as expected in step %1").arg(i).toLocal8Bit());
|
|
|
|
// any data left?
|
|
if (it->type == Chat::DiscardUntilDisconnect) {
|
|
QByteArray buffer = socket.readAll();
|
|
qDebug() << i << "Discarded in the process:" << prettyByteArray(buffer);
|
|
}
|
|
|
|
if (socket.bytesAvailable() != 0)
|
|
QFAIL(QString("Unexpected bytes still on buffer when disconnecting in step %1:\n%2")
|
|
.arg(i).arg(prettyByteArray(socket.readAll())).toLocal8Bit());
|
|
break;
|
|
|
|
case Chat::Reconnect:
|
|
qDebug() << i << "Reconnecting to server on port" << port;
|
|
socket.connectToHost(serverName, port);
|
|
QVERIFY2(socket.waitForConnected(10000),
|
|
QString("Failed to reconnect to server in step %1: %2").arg(i).arg(socket.errorString()).toLocal8Bit());
|
|
break;
|
|
|
|
case Chat::StartEncryption:
|
|
#ifdef QT_NO_SSL
|
|
QFAIL("Internal error: SSL required for this test");
|
|
#else
|
|
qDebug() << i << "Starting client encryption";
|
|
socket.ignoreSslErrors();
|
|
socket.startClientEncryption();
|
|
QVERIFY2(socket.waitForEncrypted(5000),
|
|
QString("Failed to start client encryption in step %1: %2").arg(i)
|
|
.arg(socket.errorString()).toLocal8Bit());
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
tst_NetworkSelfTest::tst_NetworkSelfTest()
|
|
{
|
|
#ifndef QT_NO_OPENSSL
|
|
qt_ForceTlsSecurityLevel();
|
|
#endif
|
|
}
|
|
|
|
tst_NetworkSelfTest::~tst_NetworkSelfTest()
|
|
{
|
|
}
|
|
|
|
QHostAddress tst_NetworkSelfTest::serverIpAddress()
|
|
{
|
|
if (cachedIpAddress.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol) {
|
|
// need resolving
|
|
QHostInfo resolved = QHostInfo::fromName(QtNetworkSettings::httpServerName());
|
|
if(resolved.error() != QHostInfo::NoError ||
|
|
resolved.addresses().isEmpty()) {
|
|
qWarning("QHostInfo::fromName failed (%d).", resolved.error());
|
|
return QHostAddress(QHostAddress::Null);
|
|
}
|
|
cachedIpAddress = resolved.addresses().first();
|
|
}
|
|
return cachedIpAddress;
|
|
}
|
|
|
|
void tst_NetworkSelfTest::initTestCase()
|
|
{
|
|
#if defined(QT_TEST_SERVER)
|
|
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::echoServerName(), 7));
|
|
// TODO: 'daytime' , port 13.
|
|
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpServerName(), 21));
|
|
const QHostInfo resolved = QHostInfo::fromName(QtNetworkSettings::ftpServerName());
|
|
if (resolved.error() == QHostInfo::NoError && !resolved.addresses().isEmpty())
|
|
ftpServerIpAddress = resolved.addresses().first();
|
|
// TODO: 'ssh', port 22.
|
|
// QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121));
|
|
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 80));
|
|
// TODO: 'smb', port 139.
|
|
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::imapServerName(), 143));
|
|
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 443));
|
|
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128));
|
|
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3129));
|
|
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3130));
|
|
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080));
|
|
QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1081));
|
|
#else
|
|
if (!QtNetworkSettings::verifyTestNetworkSettings())
|
|
QSKIP("No network test server available");
|
|
#endif
|
|
}
|
|
|
|
void tst_NetworkSelfTest::hostTest()
|
|
{
|
|
// this is a localhost self-test
|
|
QHostInfo localhost = QHostInfo::fromName("localhost");
|
|
QCOMPARE(localhost.error(), QHostInfo::NoError);
|
|
QVERIFY(!localhost.addresses().isEmpty());
|
|
|
|
QTcpServer server;
|
|
QVERIFY(server.listen());
|
|
|
|
QTcpSocket socket;
|
|
socket.connectToHost("127.0.0.1", server.serverPort());
|
|
QVERIFY(socket.waitForConnected(10000));
|
|
}
|
|
|
|
void tst_NetworkSelfTest::dnsResolution_data()
|
|
{
|
|
QTest::addColumn<QString>("hostName");
|
|
QTest::newRow("local-name") << QtNetworkSettings::serverLocalName();
|
|
QTest::newRow("fqdn") << QtNetworkSettings::httpServerName();
|
|
}
|
|
|
|
void tst_NetworkSelfTest::dnsResolution()
|
|
{
|
|
QFETCH(QString, hostName);
|
|
QHostInfo resolved = QHostInfo::fromName(hostName);
|
|
QVERIFY2(resolved.error() == QHostInfo::NoError,
|
|
QString("Failed to resolve hostname %1: %2").arg(hostName, resolved.errorString()).toLocal8Bit());
|
|
QVERIFY2(resolved.addresses().size() > 0, "Got 0 addresses for server IP");
|
|
|
|
cachedIpAddress = resolved.addresses().first();
|
|
}
|
|
|
|
void tst_NetworkSelfTest::serverReachability()
|
|
{
|
|
// check that we get a proper error connecting to port 12346
|
|
QTcpSocket socket;
|
|
socket.connectToHost(QtNetworkSettings::httpServerName(), 12346);
|
|
|
|
QElapsedTimer timer;
|
|
timer.start();
|
|
socket.waitForConnected(10000);
|
|
QVERIFY2(timer.elapsed() < 9900, "Connection to closed port timed out instead of refusing, something is wrong");
|
|
|
|
QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, "Socket connected unexpectedly!");
|
|
QVERIFY2(socket.error() == QAbstractSocket::ConnectionRefusedError,
|
|
QString("Could not reach server: %1").arg(socket.errorString()).toLocal8Bit());
|
|
}
|
|
|
|
void tst_NetworkSelfTest::remotePortsOpen_data()
|
|
{
|
|
#if defined(QT_TEST_SERVER)
|
|
QSKIP("Skipping, for the docker test server already tested by initTestCase()");
|
|
#endif
|
|
QTest::addColumn<int>("portNumber");
|
|
|
|
QTest::newRow("echo") << 7;
|
|
QTest::newRow("daytime") << 13;
|
|
QTest::newRow("ftp") << 21;
|
|
QTest::newRow("ssh") << 22;
|
|
QTest::newRow("imap") << 143;
|
|
QTest::newRow("http") << 80;
|
|
QTest::newRow("https") << 443;
|
|
QTest::newRow("http-proxy") << 3128;
|
|
QTest::newRow("http-proxy-auth-basic") << 3129;
|
|
QTest::newRow("http-proxy-auth-ntlm") << 3130;
|
|
QTest::newRow("socks5-proxy") << 1080;
|
|
QTest::newRow("socks5-proxy-auth") << 1081;
|
|
QTest::newRow("ftp-proxy") << 2121;
|
|
QTest::newRow("smb") << 139;
|
|
}
|
|
|
|
void tst_NetworkSelfTest::remotePortsOpen()
|
|
{
|
|
QFETCH(const int, portNumber);
|
|
|
|
QTcpSocket socket;
|
|
socket.connectToHost(QtNetworkSettings::hostWithServiceOnPort(portNumber), quint16(portNumber));
|
|
|
|
if (!socket.waitForConnected(10000)) {
|
|
if (socket.error() == QAbstractSocket::SocketTimeoutError)
|
|
QFAIL(QString("Network timeout connecting to the server on port %1").arg(portNumber).toLocal8Bit());
|
|
else
|
|
QFAIL(QString("Error connecting to server on port %1: %2").arg(portNumber).arg(socket.errorString()).toLocal8Bit());
|
|
}
|
|
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
|
|
}
|
|
|
|
static QList<Chat> ftpChat(const QByteArray &userSuffix = QByteArray())
|
|
{
|
|
QList<Chat> rv;
|
|
rv << Chat::expect("220")
|
|
<< Chat::discardUntil("\r\n")
|
|
<< Chat::send("USER anonymous" + userSuffix + "\r\n")
|
|
<< Chat::expect("331")
|
|
<< Chat::discardUntil("\r\n")
|
|
<< Chat::send("PASS user@hostname\r\n")
|
|
<< Chat::expect("230")
|
|
<< Chat::discardUntil("\r\n")
|
|
<< Chat::send("CWD pub\r\n")
|
|
<< Chat::expect("250")
|
|
<< Chat::discardUntil("\r\n")
|
|
<< Chat::send("CWD dir-not-readable\r\n")
|
|
<< Chat::expect("550")
|
|
<< Chat::discardUntil("\r\n")
|
|
<< Chat::send("PWD\r\n")
|
|
#if defined(QT_TEST_SERVER)
|
|
<< Chat::expect("257 \"/pub\" is the current directory\r\n")
|
|
#else
|
|
<< Chat::expect("257 \"/pub\"\r\n")
|
|
#endif
|
|
<< Chat::send("SIZE file-not-readable.txt\r\n")
|
|
<< Chat::expect("213 41\r\n")
|
|
<< Chat::send("CWD qxmlquery\r\n")
|
|
<< Chat::expect("250")
|
|
<< Chat::discardUntil("\r\n")
|
|
<< Chat::send("CWD /qtest\r\n")
|
|
<< Chat::expect("250")
|
|
<< Chat::discardUntil("\r\n")
|
|
<< Chat::send("SIZE bigfile\r\n")
|
|
<< Chat::expect("213 519240\r\n")
|
|
<< Chat::send("SIZE rfc3252\r\n")
|
|
<< Chat::expect("213 25962\r\n")
|
|
<< Chat::send("SIZE rfc3252.txt\r\n")
|
|
<< Chat::expect("213 25962\r\n")
|
|
<< Chat::send("QUIT\r\n");
|
|
|
|
rv << Chat::expect("221")
|
|
<< Chat::discardUntil("\r\n");
|
|
|
|
rv << Chat::RemoteDisconnect;
|
|
return rv;
|
|
}
|
|
|
|
void tst_NetworkSelfTest::ftpServer()
|
|
{
|
|
netChat(21, ftpChat());
|
|
}
|
|
|
|
void tst_NetworkSelfTest::ftpProxyServer()
|
|
{
|
|
QSKIP("FTP not currently supported.");
|
|
netChat(2121, ftpChat("@" + QtNetworkSettings::ftpServerName().toLatin1()));
|
|
}
|
|
|
|
void tst_NetworkSelfTest::imapServer()
|
|
{
|
|
netChat(143, QList<Chat>()
|
|
<< Chat::expect("* OK ")
|
|
<< Chat::discardUntil("\r\n")
|
|
<< Chat::send("1 CAPABILITY\r\n")
|
|
<< Chat::expect("* CAPABILITY ")
|
|
<< Chat::discardUntil("1 OK")
|
|
<< Chat::discardUntil("\r\n")
|
|
<< Chat::send("2 LOGOUT\r\n")
|
|
<< Chat::discardUntil("2 OK")
|
|
<< Chat::discardUntil("\r\n")
|
|
<< Chat::RemoteDisconnect);
|
|
}
|
|
|
|
void tst_NetworkSelfTest::httpServer()
|
|
{
|
|
QByteArray uniqueExtension = QByteArray::number((qulonglong)this) +
|
|
QByteArray::number((qulonglong)QRandomGenerator::global()->generate()) +
|
|
QByteArray::number(QDateTime::currentSecsSinceEpoch());
|
|
|
|
netChat(80, QList<Chat>()
|
|
// HTTP/0.9 chat:
|
|
<< Chat::send("GET /\r\n")
|
|
<< Chat::DiscardUntilDisconnect
|
|
|
|
// HTTP/1.0 chat:
|
|
<< Chat::Reconnect
|
|
<< Chat::send("GET / HTTP/1.0\r\n"
|
|
"Host: " + QtNetworkSettings::httpServerName().toLatin1() + "\r\n"
|
|
"Connection: close\r\n"
|
|
"\r\n")
|
|
<< Chat::expect("HTTP/1.")
|
|
<< Chat::discardUntil(" ")
|
|
<< Chat::expect("200 ")
|
|
<< Chat::DiscardUntilDisconnect
|
|
|
|
// HTTP/1.0 POST:
|
|
<< Chat::Reconnect
|
|
<< Chat::send("POST / HTTP/1.0\r\n"
|
|
"Content-Length: 5\r\n"
|
|
"Host: " + QtNetworkSettings::httpServerName().toLatin1() + "\r\n"
|
|
"Connection: close\r\n"
|
|
"\r\n"
|
|
"Hello")
|
|
<< Chat::expect("HTTP/1.")
|
|
<< Chat::discardUntil(" ")
|
|
<< Chat::expect("200 ")
|
|
<< Chat::DiscardUntilDisconnect
|
|
|
|
// HTTP protected area
|
|
<< Chat::Reconnect
|
|
<< Chat::send("GET /qtest/protected/rfc3252.txt HTTP/1.0\r\n"
|
|
"Host: " + QtNetworkSettings::httpServerName().toLatin1() + "\r\n"
|
|
"Connection: close\r\n"
|
|
"\r\n")
|
|
<< Chat::expect("HTTP/1.")
|
|
<< Chat::discardUntil(" ")
|
|
<< Chat::expect("401 ")
|
|
<< Chat::DiscardUntilDisconnect
|
|
|
|
<< Chat::Reconnect
|
|
<< Chat::send("HEAD /qtest/protected/rfc3252.txt HTTP/1.0\r\n"
|
|
"Host: " + QtNetworkSettings::httpServerName().toLatin1() + "\r\n"
|
|
"Connection: close\r\n"
|
|
"Authorization: Basic cXNvY2tzdGVzdDpwYXNzd29yZA==\r\n"
|
|
"\r\n")
|
|
<< Chat::expect("HTTP/1.")
|
|
<< Chat::discardUntil(" ")
|
|
<< Chat::expect("200 ")
|
|
<< Chat::DiscardUntilDisconnect
|
|
|
|
// DAV area
|
|
<< Chat::Reconnect
|
|
<< Chat::send("HEAD /dav/ HTTP/1.0\r\n"
|
|
"Host: " + QtNetworkSettings::httpServerName().toLatin1() + "\r\n"
|
|
"Connection: close\r\n"
|
|
"\r\n")
|
|
<< Chat::expect("HTTP/1.")
|
|
<< Chat::discardUntil(" ")
|
|
<< Chat::expect("200 ")
|
|
<< Chat::DiscardUntilDisconnect
|
|
|
|
// HTTP/1.0 PUT
|
|
<< Chat::Reconnect
|
|
<< Chat::send("PUT /dav/networkselftest-" + uniqueExtension + ".txt HTTP/1.0\r\n"
|
|
"Content-Length: 5\r\n"
|
|
"Host: " + QtNetworkSettings::httpServerName().toLatin1() + "\r\n"
|
|
"Connection: close\r\n"
|
|
"\r\n"
|
|
"Hello")
|
|
<< Chat::expect("HTTP/1.")
|
|
<< Chat::discardUntil(" ")
|
|
<< Chat::expect("201 ")
|
|
<< Chat::DiscardUntilDisconnect
|
|
|
|
// check that the file did get uploaded
|
|
<< Chat::Reconnect
|
|
<< Chat::send("HEAD /dav/networkselftest-" + uniqueExtension + ".txt HTTP/1.0\r\n"
|
|
"Host: " + QtNetworkSettings::httpServerName().toLatin1() + "\r\n"
|
|
"Connection: close\r\n"
|
|
"\r\n")
|
|
<< Chat::expect("HTTP/1.")
|
|
<< Chat::discardUntil(" ")
|
|
<< Chat::expect("200 ")
|
|
<< Chat::discardUntil("\r\nContent-Length: 5\r\n")
|
|
<< Chat::DiscardUntilDisconnect
|
|
|
|
// HTTP/1.0 DELETE
|
|
<< Chat::Reconnect
|
|
<< Chat::send("DELETE /dav/networkselftest-" + uniqueExtension + ".txt HTTP/1.0\r\n"
|
|
"Host: " + QtNetworkSettings::httpServerName().toLatin1() + "\r\n"
|
|
"Connection: close\r\n"
|
|
"\r\n")
|
|
<< Chat::expect("HTTP/1.")
|
|
<< Chat::discardUntil(" ")
|
|
<< Chat::expect("204 ")
|
|
<< Chat::DiscardUntilDisconnect
|
|
);
|
|
}
|
|
|
|
void tst_NetworkSelfTest::httpServerFiles_data()
|
|
{
|
|
QTest::addColumn<QString>("uri");
|
|
QTest::addColumn<int>("size");
|
|
|
|
QTest::newRow("fluke.gif") << "/qtest/fluke.gif" << -1;
|
|
QTest::newRow("bigfile") << "/qtest/bigfile" << 519240;
|
|
QTest::newRow("rfc3252.txt") << "/qtest/rfc3252.txt" << 25962;
|
|
QTest::newRow("protected/rfc3252.txt") << "/qtest/protected/rfc3252.txt" << 25962;
|
|
QTest::newRow("completelyEmptyQuery.xq") << "/qtest/qxmlquery/completelyEmptyQuery.xq" << -1;
|
|
QTest::newRow("notWellformedViaHttps.xml") << "/qtest/qxmlquery/notWellformedViaHttps.xml" << -1;
|
|
QTest::newRow("notWellformed.xml") << "/qtest/qxmlquery/notWellformed.xml" << -1;
|
|
QTest::newRow("viaHttp.xq") << "/qtest/qxmlquery/viaHttp.xq" << -1;
|
|
QTest::newRow("wellFormedViaHttps.xml") << "/qtest/qxmlquery/wellFormedViaHttps.xml" << -1;
|
|
QTest::newRow("wellFormed.xml") << "/qtest/qxmlquery/wellFormed.xml" << -1;
|
|
}
|
|
|
|
void tst_NetworkSelfTest::httpServerFiles()
|
|
{
|
|
QFETCH(QString, uri);
|
|
QFETCH(int, size);
|
|
QUrl url(uri);
|
|
|
|
QList<Chat> chat;
|
|
chat << Chat::send("HEAD " + url.toEncoded() + " HTTP/1.0\r\n"
|
|
"Host: " + QtNetworkSettings::httpServerName().toLatin1() + "\r\n"
|
|
"Connection: close\r\n"
|
|
"Authorization: Basic cXNvY2tzdGVzdDpwYXNzd29yZA==\r\n"
|
|
"\r\n")
|
|
<< Chat::expect("HTTP/1.")
|
|
<< Chat::skipBytes(1) // HTTP/1.0 or 1.1 reply
|
|
<< Chat::expect(" 200 ");
|
|
if (size != -1)
|
|
chat << Chat::discardUntil("\r\nContent-Length: " + QByteArray::number(size) + "\r\n");
|
|
chat << Chat::DiscardUntilDisconnect;
|
|
netChat(80, chat);
|
|
}
|
|
|
|
void tst_NetworkSelfTest::httpServerCGI_data()
|
|
{
|
|
QTest::addColumn<QByteArray>("request");
|
|
QTest::addColumn<QByteArray>("result");
|
|
QTest::addColumn<QByteArray>("additionalHeader");
|
|
|
|
QTest::newRow("echo.cgi")
|
|
<< QByteArray("GET /qtest/cgi-bin/echo.cgi?Hello+World HTTP/1.0\r\n"
|
|
"Connection: close\r\n"
|
|
"\r\n")
|
|
<< QByteArray("Hello+World")
|
|
<< QByteArray();
|
|
|
|
QTest::newRow("echo.cgi(POST)")
|
|
<< QByteArray("POST /qtest/cgi-bin/echo.cgi?Hello+World HTTP/1.0\r\n"
|
|
"Connection: close\r\n"
|
|
"Content-Length: 15\r\n"
|
|
"\r\n"
|
|
"Hello, World!\r\n")
|
|
<< QByteArray("Hello, World!\r\n")
|
|
<< QByteArray();
|
|
|
|
QTest::newRow("md5sum.cgi")
|
|
<< QByteArray("POST /qtest/cgi-bin/md5sum.cgi HTTP/1.0\r\n"
|
|
"Connection: close\r\n"
|
|
"Content-Length: 15\r\n"
|
|
"\r\n"
|
|
"Hello, World!\r\n")
|
|
<< QByteArray("29b933a8d9a0fcef0af75f1713f4940e\n")
|
|
<< QByteArray();
|
|
|
|
QTest::newRow("protected/md5sum.cgi")
|
|
<< QByteArray("POST /qtest/protected/cgi-bin/md5sum.cgi HTTP/1.0\r\n"
|
|
"Connection: close\r\n"
|
|
"Authorization: Basic cXNvY2tzdGVzdDpwYXNzd29yZA==\r\n"
|
|
"Content-Length: 15\r\n"
|
|
"\r\n"
|
|
"Hello, World!\r\n")
|
|
<< QByteArray("29b933a8d9a0fcef0af75f1713f4940e\n")
|
|
<< QByteArray();
|
|
|
|
QTest::newRow("set-cookie.cgi")
|
|
<< QByteArray("POST /qtest/cgi-bin/set-cookie.cgi HTTP/1.0\r\n"
|
|
"Connection: close\r\n"
|
|
"Content-Length: 8\r\n"
|
|
"\r\n"
|
|
"foo=bar\n")
|
|
<< QByteArray("Success\n")
|
|
<< QByteArray("\r\nSet-Cookie: foo=bar\r\n");
|
|
}
|
|
|
|
void tst_NetworkSelfTest::httpServerCGI()
|
|
{
|
|
QFETCH(QByteArray, request);
|
|
QFETCH(QByteArray, result);
|
|
QFETCH(QByteArray, additionalHeader);
|
|
QList<Chat> chat;
|
|
chat << Chat::send(request)
|
|
<< Chat::expect("HTTP/1.") << Chat::skipBytes(1)
|
|
<< Chat::expect(" 200 ");
|
|
|
|
if (!additionalHeader.isEmpty())
|
|
chat << Chat::discardUntil(additionalHeader);
|
|
|
|
chat << Chat::discardUntil("\r\n\r\n")
|
|
<< Chat::expect(result)
|
|
<< Chat::RemoteDisconnect;
|
|
netChat(80, chat);
|
|
}
|
|
|
|
#ifndef QT_NO_SSL
|
|
void tst_NetworkSelfTest::httpsServer()
|
|
{
|
|
netChat(443, QList<Chat>()
|
|
<< Chat::StartEncryption
|
|
<< Chat::send("GET / HTTP/1.0\r\n"
|
|
"Host: " + QtNetworkSettings::httpServerName().toLatin1() + "\r\n"
|
|
"Connection: close\r\n"
|
|
"\r\n")
|
|
<< Chat::expect("HTTP/1.")
|
|
<< Chat::discardUntil(" ")
|
|
<< Chat::expect("200 ")
|
|
<< Chat::DiscardUntilDisconnect);
|
|
}
|
|
#endif
|
|
|
|
void tst_NetworkSelfTest::httpProxy |