summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/network/CMakeLists.txt7
-rw-r--r--src/network/access/access.pri10
-rw-r--r--src/network/access/qftp.cpp2456
-rw-r--r--src/network/access/qftp_p.h176
-rw-r--r--src/network/access/qnetworkaccesscachebackend.cpp3
-rw-r--r--src/network/access/qnetworkaccessfilebackend.cpp3
-rw-r--r--src/network/access/qnetworkaccessftpbackend.cpp436
-rw-r--r--src/network/access/qnetworkaccessftpbackend_p.h126
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp10
-rw-r--r--src/network/configure.cmake8
-rw-r--r--src/network/configure.json9
-rw-r--r--src/network/doc/snippets/code/src_network_access_qftp.cpp109
-rw-r--r--src/network/doc/src/examples.qdoc1
-rw-r--r--src/network/doc/src/network-programming.qdoc4
-rw-r--r--src/network/kernel/kernel.pri5
-rw-r--r--src/network/kernel/qurlinfo.cpp727
-rw-r--r--src/network/kernel/qurlinfo_p.h133
-rw-r--r--tests/auto/network/access/CMakeLists.txt3
-rw-r--r--tests/auto/network/access/access.pro2
-rw-r--r--tests/auto/network/access/qftp/.gitattributes1
-rw-r--r--tests/auto/network/access/qftp/.gitignore2
-rw-r--r--tests/auto/network/access/qftp/BLACKLIST16
-rw-r--r--tests/auto/network/access/qftp/CMakeLists.txt25
-rw-r--r--tests/auto/network/access/qftp/qftp.pro11
-rw-r--r--tests/auto/network/access/qftp/rfc3252.txt899
-rw-r--r--tests/auto/network/access/qftp/tst_qftp.cpp2317
-rw-r--r--tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp197
27 files changed, 104 insertions, 7592 deletions
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
index b42a4fc117..e54582c299 100644
--- a/src/network/CMakeLists.txt
+++ b/src/network/CMakeLists.txt
@@ -70,13 +70,6 @@ qt_extend_target(Network CONDITION MSVC AND (TEST_architecture_arch STREQUAL "i3
"/BASE:0x64000000"
)
-qt_extend_target(Network CONDITION QT_FEATURE_ftp
- SOURCES
- access/qftp.cpp access/qftp_p.h
- access/qnetworkaccessftpbackend.cpp access/qnetworkaccessftpbackend_p.h
- kernel/qurlinfo.cpp kernel/qurlinfo_p.h
-)
-
qt_extend_target(Network CONDITION QT_FEATURE_networkdiskcache
SOURCES
access/qnetworkdiskcache.cpp access/qnetworkdiskcache.h access/qnetworkdiskcache_p.h
diff --git a/src/network/access/access.pri b/src/network/access/access.pri
index af49fe2bb4..575effb2f0 100644
--- a/src/network/access/access.pri
+++ b/src/network/access/access.pri
@@ -46,16 +46,6 @@ SOURCES += \
access/qhsts.cpp \
access/qhstspolicy.cpp
-qtConfig(ftp) {
- HEADERS += \
- access/qftp_p.h \
- access/qnetworkaccessftpbackend_p.h
-
- SOURCES += \
- access/qftp.cpp \
- access/qnetworkaccessftpbackend.cpp
-}
-
qtConfig(networkdiskcache) {
HEADERS += \
access/qnetworkdiskcache_p.h \
diff --git a/src/network/access/qftp.cpp b/src/network/access/qftp.cpp
deleted file mode 100644
index 878f55f604..0000000000
--- a/src/network/access/qftp.cpp
+++ /dev/null
@@ -1,2456 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//#define QFTPPI_DEBUG
-//#define QFTPDTP_DEBUG
-
-#include "private/qftp_p.h"
-#include "qabstractsocket.h"
-
-#include "qcoreapplication.h"
-#include "qtcpsocket.h"
-#include "qurlinfo_p.h"
-#include "qstringlist.h"
-#include "qregularexpression.h"
-#include "qtimer.h"
-#include "qfileinfo.h"
-#include "qtcpserver.h"
-#include "qlocale.h"
-
-QT_BEGIN_NAMESPACE
-
-class QFtpPI;
-
-/*
- The QFtpDTP (DTP = Data Transfer Process) controls all client side
- data transfer between the client and server.
-*/
-class QFtpDTP : public QObject
-{
- Q_OBJECT
-
-public:
- enum ConnectState {
- CsHostFound,
- CsConnected,
- CsClosed,
- CsHostNotFound,
- CsConnectionRefused
- };
-
- QFtpDTP(QFtpPI *p, QObject *parent = nullptr);
-
- void setData(QByteArray *);
- void setDevice(QIODevice *);
- void writeData();
- void setBytesTotal(qint64 bytes);
-
- bool hasError() const;
- QString errorMessage() const;
- void clearError();
-
- void connectToHost(const QString & host, quint16 port);
- int setupListener(const QHostAddress &address);
- void waitForConnection();
-
- QTcpSocket::SocketState state() const;
- qint64 bytesAvailable() const;
- qint64 read(char *data, qint64 maxlen);
- QByteArray readAll();
-
- void abortConnection();
-
- static bool parseDir(const QByteArray &buffer, const QString &userName, QUrlInfo *info);
-
-signals:
- void listInfo(const QUrlInfo&);
- void readyRead();
- void dataTransferProgress(qint64, qint64);
-
- void connectState(int);
-
-private slots:
- void socketConnected();
- void socketReadyRead();
- void socketError(QAbstractSocket::SocketError);
- void socketConnectionClosed();
- void socketBytesWritten(qint64);
- void setupSocket();
-
- void dataReadyRead();
-
-private:
- void clearData();
-
- QTcpSocket *socket;
- QTcpServer listener;
-
- QFtpPI *pi;
- QString err;
- qint64 bytesDone;
- qint64 bytesTotal;
- bool callWriteData;
-
- // If is_ba is true, ba is used; ba is never 0.
- // Otherwise dev is used; dev can be 0 or not.
- union {
- QByteArray *ba;
- QIODevice *dev;
- } data;
- bool is_ba;
-
- QByteArray bytesFromSocket;
-};
-
-/**********************************************************************
- *
- * QFtpPI - Protocol Interpreter
- *
- *********************************************************************/
-
-class QFtpPI : public QObject
-{
- Q_OBJECT
-
-public:
- QFtpPI(QObject *parent = nullptr);
-
- void connectToHost(const QString &host, quint16 port);
-
- bool sendCommands(const QStringList &cmds);
- bool sendCommand(const QString &cmd)
- { return sendCommands(QStringList(cmd)); }
-
- void clearPendingCommands();
- void abort();
-
- QString currentCommand() const
- { return currentCmd; }
-
- bool rawCommand;
- bool transferConnectionExtended;
-
- QFtpDTP dtp; // the PI has a DTP which is not the design of RFC 959, but it
- // makes the design simpler this way
-signals:
- void connectState(int);
- void finished(const QString&);
- void error(int, const QString&);
- void rawFtpReply(int, const QString&);
-
-private slots:
- void hostFound();
- void connected();
- void connectionClosed();
- void delayedCloseFinished();
- void readyRead();
- void error(QAbstractSocket::SocketError);
-
- void dtpConnectState(int);
-
-private:
- // the states are modelled after the generalized state diagram of RFC 959,
- // page 58
- enum State {
- Begin,
- Idle,
- Waiting,
- Success,
- Failure
- };
-
- enum AbortState {
- None,
- AbortStarted,
- WaitForAbortToFinish
- };
-
- bool processReply();
- bool startNextCmd();
-
- QTcpSocket commandSocket;
- QString replyText;
- char replyCode[3];
- State state;
- AbortState abortState;
- QStringList pendingCommands;
- QString currentCmd;
-
- bool waitForDtpToConnect;
- bool waitForDtpToClose;
-
- QByteArray bytesFromSocket;
-
- friend class QFtpDTP;
-};
-
-/**********************************************************************
- *
- * QFtpCommand implemenatation
- *
- *********************************************************************/
-class QFtpCommand
-{
-public:
- QFtpCommand(QFtp::Command cmd, const QStringList &raw, const QByteArray &ba);
- QFtpCommand(QFtp::Command cmd, const QStringList &raw, QIODevice *dev = nullptr);
- ~QFtpCommand();
-
- int id;
- QFtp::Command command;
- QStringList rawCmds;
-
- // If is_ba is true, ba is used; ba is never 0.
- // Otherwise dev is used; dev can be 0 or not.
- union {
- QByteArray *ba;
- QIODevice *dev;
- } data;
- bool is_ba;
-
-};
-
-static int nextId()
-{
- static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
- return 1 + counter.fetchAndAddRelaxed(1);
-}
-
-QFtpCommand::QFtpCommand(QFtp::Command cmd, const QStringList &raw, const QByteArray &ba)
- : command(cmd), rawCmds(raw), is_ba(true)
-{
- id = nextId();
- data.ba = new QByteArray(ba);
-}
-
-QFtpCommand::QFtpCommand(QFtp::Command cmd, const QStringList &raw, QIODevice *dev)
- : command(cmd), rawCmds(raw), is_ba(false)
-{
- id = nextId();
- data.dev = dev;
-}
-
-QFtpCommand::~QFtpCommand()
-{
- if (is_ba)
- delete data.ba;
-}
-
-/**********************************************************************
- *
- * QFtpDTP implemenatation
- *
- *********************************************************************/
-QFtpDTP::QFtpDTP(QFtpPI *p, QObject *parent) :
- QObject(parent),
- socket(nullptr),
- listener(this),
- pi(p),
- callWriteData(false)
-{
- clearData();
- listener.setObjectName(QLatin1String("QFtpDTP active state server"));
- connect(&listener, SIGNAL(newConnection()), SLOT(setupSocket()));
-}
-
-void QFtpDTP::setData(QByteArray *ba)
-{
- is_ba = true;
- data.ba = ba;
-}
-
-void QFtpDTP::setDevice(QIODevice *dev)
-{
- is_ba = false;
- data.dev = dev;
-}
-
-void QFtpDTP::setBytesTotal(qint64 bytes)
-{
- bytesTotal = bytes;
- bytesDone = 0;
- emit dataTransferProgress(bytesDone, bytesTotal);
-}
-
-void QFtpDTP::connectToHost(const QString & host, quint16 port)
-{
- bytesFromSocket.clear();
-
- if (socket) {
- delete socket;
- socket = nullptr;
- }
- socket = new QTcpSocket(this);
- socket->setObjectName(QLatin1String("QFtpDTP Passive state socket"));
- connect(socket, SIGNAL(connected()), SLOT(socketConnected()));
- connect(socket, SIGNAL(readyRead()), SLOT(socketReadyRead()));
- connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError)));
- connect(socket, SIGNAL(disconnected()), SLOT(socketConnectionClosed()));
- connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64)));
-
- socket->connectToHost(host, port);
-}
-
-int QFtpDTP::setupListener(const QHostAddress &address)
-{
- if (!listener.isListening() && !listener.listen(address, 0))
- return -1;
- return listener.serverPort();
-}
-
-void QFtpDTP::waitForConnection()
-{
- // This function is only interesting in Active transfer mode; it works
- // around a limitation in QFtp's design by blocking, waiting for an
- // incoming connection. For the default Passive mode, it does nothing.
- if (listener.isListening())
- listener.waitForNewConnection();
-}
-
-QTcpSocket::SocketState QFtpDTP::state() const
-{
- return socket ? socket->state() : QTcpSocket::UnconnectedState;
-}
-
-qint64 QFtpDTP::bytesAvailable() const
-{
- if (!socket || socket->state() != QTcpSocket::ConnectedState)
- return (qint64) bytesFromSocket.size();
- return socket->bytesAvailable();
-}
-
-qint64 QFtpDTP::read(char *data, qint64 maxlen)
-{
- qint64 read;
- if (socket && socket->state() == QTcpSocket::ConnectedState) {
- read = socket->read(data, maxlen);
- } else {
- read = qMin(maxlen, qint64(bytesFromSocket.size()));
- memcpy(data, bytesFromSocket.data(), read);
- bytesFromSocket.remove(0, read);
- }
-
- bytesDone += read;
- return read;
-}
-
-QByteArray QFtpDTP::readAll()
-{
- QByteArray tmp;
- if (socket && socket->state() == QTcpSocket::ConnectedState) {
- tmp = socket->readAll();
- bytesDone += tmp.size();
- } else {
- tmp = bytesFromSocket;
- bytesFromSocket.clear();
- }
- return tmp;
-}
-
-void QFtpDTP::writeData()
-{
- if (!socket)
- return;
-
- if (is_ba) {
-#if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::writeData: write %d bytes", data.ba->size());
-#endif
- if (data.ba->size() == 0)
- emit dataTransferProgress(0, bytesTotal);
- else
- socket->write(data.ba->data(), data.ba->size());
-
- socket->close();
-
- clearData();
- } else if (data.dev) {
- callWriteData = false;
- const qint64 blockSize = 16*1024;
- char buf[16*1024];
- qint64 read = data.dev->read(buf, blockSize);
-#if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::writeData: write() of size %lli bytes", read);
-#endif
- if (read > 0) {
- socket->write(buf, read);
- } else if (read == -1 || (!data.dev->isSequential() && data.dev->atEnd())) {
- // error or EOF
- if (bytesDone == 0 && socket->bytesToWrite() == 0)
- emit dataTransferProgress(0, bytesTotal);
- socket->close();
- clearData();
- }
-
- // do we continue uploading?
- callWriteData = data.dev != nullptr;
- }
-}
-
-void QFtpDTP::dataReadyRead()
-{
- writeData();
-}
-
-inline bool QFtpDTP::hasError() const
-{
- return !err.isNull();
-}
-
-inline QString QFtpDTP::errorMessage() const
-{
- return err;
-}
-
-inline void QFtpDTP::clearError()
-{
- err.clear();
-}
-
-void QFtpDTP::abortConnection()
-{
-#if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::abortConnection, bytesAvailable == %lli",
- socket ? socket->bytesAvailable() : (qint64) 0);
-#endif
- callWriteData = false;
- clearData();
-
- if (socket)
- socket->abort();
-}
-
-static void _q_fixupDateTime(QDateTime *dateTime)
-{
- // Adjust for future tolerance.
- const int futureTolerance = 86400;
- if (dateTime->secsTo(QDateTime::currentDateTime()) < -futureTolerance) {
- QDate d = dateTime->date();
- d.setDate(d.year() - 1, d.month(), d.day());
- dateTime->setDate(d);
- }
-}
-
-static void _q_parseUnixDir(const QStringList &tokens, const QString &userName, QUrlInfo *info)
-{
- // Unix style, 7 + 1 entries
- // -rw-r--r-- 1 ftp ftp 17358091 Aug 10 2004 qt-x11-free-3.3.3.tar.gz
- // drwxr-xr-x 3 ftp ftp 4096 Apr 14 2000 compiled-examples
- // lrwxrwxrwx 1 ftp ftp 9 Oct 29 2005 qtscape -> qtmozilla
- if (tokens.size() != 8)
- return;
-
- char first = tokens.at(1).at(0).toLatin1();
- if (first == 'd') {
- info->setDir(true);
- info->setFile(false);
- info->setSymLink(false);
- } else if (first == '-') {
- info->setDir(false);
- info->setFile(true);
- info->setSymLink(false);
- } else if (first == 'l') {
- info->setDir(true);
- info->setFile(false);
- info->setSymLink(true);
- }
-
- // Resolve filename
- QString name = tokens.at(7);
- if (info->isSymLink()) {
- int linkPos = name.indexOf(QLatin1String(" ->"));
- if (linkPos != -1)
- name.resize(linkPos);
- }
- info->setName(name);
-
- // Resolve owner & group
- info->setOwner(tokens.at(3));
- info->setGroup(tokens.at(4));
-
- // Resolve size
- info->setSize(tokens.at(5).toLongLong());
-
- QStringList formats;
- formats << QLatin1String("MMM dd yyyy") << QLatin1String("MMM dd hh:mm") << QLatin1String("MMM d yyyy")
- << QLatin1String("MMM d hh:mm") << QLatin1String("MMM d yyyy") << QLatin1String("MMM dd yyyy");
-
- QString dateString = tokens.at(6);
- dateString[0] = dateString[0].toUpper();
-
- // Resolve the modification date by parsing all possible formats
- QDateTime dateTime;
- int n = 0;
-#if QT_CONFIG(datetimeparser)
- do {
- dateTime = QLocale::c().toDateTime(dateString, formats.at(n++));
- } while (n < formats.size() && (!dateTime.isValid()));
-#endif
-
- if (n == 2 || n == 4) {
- // Guess the year.
- dateTime.setDate(QDate(QDate::currentDate().year(),
- dateTime.date().month(),
- dateTime.date().day()));
- _q_fixupDateTime(&dateTime);
- }
- if (dateTime.isValid())
- info->setLastModified(dateTime);
-
- // Resolve permissions
- int permissions = 0;
- const QString &p = tokens.at(2);
- permissions |= (p[0] == QLatin1Char('r') ? QUrlInfo::ReadOwner : 0);
- permissions |= (p[1] == QLatin1Char('w') ? QUrlInfo::WriteOwner : 0);
- permissions |= (p[2] == QLatin1Char('x') ? QUrlInfo::ExeOwner : 0);
- permissions |= (p[3] == QLatin1Char('r') ? QUrlInfo::ReadGroup : 0);
- permissions |= (p[4] == QLatin1Char('w') ? QUrlInfo::WriteGroup : 0);
- permissions |= (p[5] == QLatin1Char('x') ? QUrlInfo::ExeGroup : 0);
- permissions |= (p[6] == QLatin1Char('r') ? QUrlInfo::ReadOther : 0);
- permissions |= (p[7] == QLatin1Char('w') ? QUrlInfo::WriteOther : 0);
- permissions |= (p[8] == QLatin1Char('x') ? QUrlInfo::ExeOther : 0);
- info->setPermissions(permissions);
-
- bool isOwner = info->owner() == userName;
- info->setReadable((permissions & QUrlInfo::ReadOther) || ((permissions & QUrlInfo::ReadOwner) && isOwner));
- info->setWritable((permissions & QUrlInfo::WriteOther) || ((permissions & QUrlInfo::WriteOwner) && isOwner));
-}
-
-static void _q_parseDosDir(const QStringList &tokens, const QString &userName, QUrlInfo *info)
-{
- // DOS style, 3 + 1 entries
- // 01-16-02 11:14AM <DIR> epsgroup
- // 06-05-03 03:19PM 1973 readme.txt
- if (tokens.size() != 4)
- return;
-
- Q_UNUSED(userName);
-
- QString name = tokens.at(3);
- info->setName(name);
- info->setSymLink(name.endsWith(QLatin1String(".lnk"), Qt::CaseInsensitive));
-
- if (tokens.at(2) == QLatin1String("<DIR>")) {
- info->setFile(false);
- info->setDir(true);
- } else {
- info->setFile(true);
- info->setDir(false);
- info->setSize(tokens.at(2).toLongLong());
- }
-
- // Note: We cannot use QFileInfo; permissions are for the server-side
- // machine, and QFileInfo's behavior depends on the local platform.
- int permissions = QUrlInfo::ReadOwner | QUrlInfo::WriteOwner
- | QUrlInfo::ReadGroup | QUrlInfo::WriteGroup
- | QUrlInfo::ReadOther | QUrlInfo::WriteOther;
- QStringView ext;
- int extIndex = name.lastIndexOf(QLatin1Char('.'));
- if (extIndex != -1)
- ext = QStringView{name}.mid(extIndex + 1);
- if (ext == QLatin1String("exe") || ext == QLatin1String("bat") || ext == QLatin1String("com"))
- permissions |= QUrlInfo::ExeOwner | QUrlInfo::ExeGroup | QUrlInfo::ExeOther;
- info->setPermissions(permissions);
-
- info->setReadable(true);
- info->setWritable(info->isFile());
-
- QDateTime dateTime;
-#if QT_CONFIG(datetimeparser)
- dateTime = QLocale::c().toDateTime(tokens.at(1), QLatin1String("MM-dd-yy hh:mmAP"));
- if (dateTime.date().year() < 1971) {
- dateTime.setDate(QDate(dateTime.date().year() + 100,
- dateTime.date().month(),
- dateTime.date().day()));
- }
-#endif
-
- info->setLastModified(dateTime);
-
-}
-
-bool QFtpDTP::parseDir(const QByteArray &buffer, const QString &userName, QUrlInfo *info)
-{
- if (buffer.isEmpty())
- return false;
-
- QString bufferStr = QString::fromUtf8(buffer).trimmed();
-
- // Unix style FTP servers
- QRegularExpression unixPattern(QLatin1String("^([\\-dl])([a-zA-Z\\-]{9,9})\\s+\\d+\\s+(\\S*)\\s+"
- "(\\S*)\\s+(\\d+)\\s+(\\S+\\s+\\S+\\s+\\S+)\\s+(\\S.*)"));
- auto unixPatternMatch = unixPattern.match(bufferStr);
- if (unixPatternMatch.hasMatch()) {
- _q_parseUnixDir(unixPatternMatch.capturedTexts(), userName, info);
- return true;
- }
-
- // DOS style FTP servers
- QRegularExpression dosPattern(QLatin1String("^(\\d\\d-\\d\\d-\\d\\d\\ \\ \\d\\d:\\d\\d[AP]M)\\s+"
- "(<DIR>|\\d+)\\s+(\\S.*)$"));
- auto dosPatternMatch = dosPattern.match(bufferStr);
- if (dosPatternMatch.hasMatch()) {
- _q_parseDosDir(dosPatternMatch.capturedTexts(), userName, info);
- return true;
- }
-
- // Unsupported
- return false;
-}
-
-void QFtpDTP::socketConnected()
-{
- bytesDone = 0;
-#if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::connectState(CsConnected)");
-#endif
- emit connectState(QFtpDTP::CsConnected);
-}
-
-void QFtpDTP::socketReadyRead()
-{
- if (!socket)
- return;
-
- if (pi->currentCommand().isEmpty()) {
- socket->close();
-#if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::connectState(CsClosed)");
-#endif
- emit connectState(QFtpDTP::CsClosed);
- return;
- }
-
- if (pi->abortState != QFtpPI::None) {
- // discard data
- socket->readAll();
- return;
- }
-
- if (pi->currentCommand().startsWith(QLatin1String("LIST"))) {
- while (socket->canReadLine()) {
- QUrlInfo i;
- QByteArray line = socket->readLine();
-#if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP read (list): '%s'", line.constData());
-#endif
- if (parseDir(line, QLatin1String(""), &i)) {
- emit listInfo(i);
- } else {
- // some FTP servers don't return a 550 if the file or directory
- // does not exist, but rather write a text to the data socket
- // -- try to catch these cases
- if (line.endsWith("No such file or directory\r\n"))
- err = QString::fromUtf8(line);
- }
- }
- } else {
- if (!is_ba && data.dev) {
- do {
- QByteArray ba;
- ba.resize(socket->bytesAvailable());
- qint64 bytesRead = socket->read(ba.data(), ba.size());
- if (bytesRead < 0) {
- // a read following a readyRead() signal will
- // never fail.
- return;
- }
- ba.resize(bytesRead);
- bytesDone += bytesRead;
-#if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP read: %lli bytes (total %lli bytes)", bytesRead, bytesDone);
-#endif
- if (data.dev) // make sure it wasn't deleted in the slot
- data.dev->write(ba);
- emit dataTransferProgress(bytesDone, bytesTotal);
-
- // Need to loop; dataTransferProgress is often connected to
- // slots that update the GUI (e.g., progress bar values), and
- // if events are processed, more data may have arrived.
- } while (socket->bytesAvailable());
- } else {
-#if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP readyRead: %lli bytes available (total %lli bytes read)",
- bytesAvailable(), bytesDone);
-#endif
- emit dataTransferProgress(bytesDone+socket->bytesAvailable(), bytesTotal);
- emit readyRead();
- }
- }
-}
-
-void QFtpDTP::socketError(QAbstractSocket::SocketError e)
-{
- if (e == QTcpSocket::HostNotFoundError) {
-#if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::connectState(CsHostNotFound)");
-#endif
- emit connectState(QFtpDTP::CsHostNotFound);
- } else if (e == QTcpSocket::ConnectionRefusedError) {
-#if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::connectState(CsConnectionRefused)");
-#endif
- emit connectState(QFtpDTP::CsConnectionRefused);
- }
-}
-
-void QFtpDTP::socketConnectionClosed()
-{
- if (!is_ba && data.dev) {
- clearData();
- }
-
- if (socket->isOpen())
- bytesFromSocket = socket->readAll();
- else
- bytesFromSocket.clear();
-#if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::connectState(CsClosed)");
-#endif
- emit connectState(QFtpDTP::CsClosed);
-}
-
-void QFtpDTP::socketBytesWritten(qint64 bytes)
-{
- bytesDone += bytes;
-#if defined(QFTPDTP_DEBUG)
- qDebug("QFtpDTP::bytesWritten(%lli)", bytesDone);
-#endif
- emit dataTransferProgress(bytesDone, bytesTotal);
- if (callWriteData)
- writeData();
-}
-
-void QFtpDTP::setupSocket()
-{
- socket = listener.nextPendingConnection();
- socket->setObjectName(QLatin1String("QFtpDTP Active state socket"));
- connect(socket, SIGNAL(connected()), SLOT(socketConnected()));
- connect(socket, SIGNAL(readyRead()), SLOT(socketReadyRead()));
- connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError)));
- connect(socket, SIGNAL(disconnected()), SLOT(socketConnectionClosed()));
- connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten(qint64)));
-
- listener.close();
-}
-
-void QFtpDTP::clearData()
-{
- is_ba = false;
- data.dev = nullptr;
-}
-
-/**********************************************************************
- *
- * QFtpPI implemenatation
- *
- *********************************************************************/
-QFtpPI::QFtpPI(QObject *parent) :
- QObject(parent),
- rawCommand(false),
- transferConnectionExtended(true),
- dtp(this),
- commandSocket(nullptr),
- state(Begin), abortState(None),
- currentCmd(QString()),
- waitForDtpToConnect(false),
- waitForDtpToClose(false)
-{
- commandSocket.setObjectName(QLatin1String("QFtpPI_socket"));
- connect(&commandSocket, SIGNAL(hostFound()),
- SLOT(hostFound()));
- connect(&commandSocket, SIGNAL(connected()),
- SLOT(connected()));
- connect(&commandSocket, SIGNAL(disconnected()),
- SLOT(connectionClosed()));
- connect(&commandSocket, SIGNAL(readyRead()),
- SLOT(readyRead()));
- connect(&commandSocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
- SLOT(error(QAbstractSocket::SocketError)));
-
- connect(&dtp, SIGNAL(connectState(int)),
- SLOT(dtpConnectState(int)));
-}
-
-void QFtpPI::connectToHost(const QString &host, quint16 port)
-{
- emit connectState(QFtp::HostLookup);
- commandSocket.connectToHost(host, port);
-}
-
-/*
- \internal
-
- Sends the sequence of commands \a cmds to the FTP server. When the commands
- are all done the finished() signal is emitted. When an error occurs, the
- error() signal is emitted.
-
- If there are pending commands in the queue this functions returns \c false and
- the \a cmds are not added to the queue; otherwise it returns \c true.
-*/
-bool QFtpPI::sendCommands(const QStringList &cmds)
-{
- if (!pendingCommands.isEmpty())
- return false;
-
- if (commandSocket.state() != QTcpSocket::ConnectedState || state!=Idle) {
- emit error(QFtp::NotConnected, QFtp::tr("Not connected"));
- return true; // there are no pending commands
- }
-
- pendingCommands = cmds;
- startNextCmd();
- return true;
-}
-
-void QFtpPI::clearPendingCommands()
-{
- pendingCommands.clear();
- dtp.abortConnection();
- currentCmd.clear();
- state = Idle;
-}
-
-void QFtpPI::abort()
-{
- pendingCommands.clear();
-
- if (abortState != None)
- // ABOR already sent
- return;
-
- if (currentCmd.isEmpty())
- return; //no command in progress
-
- if (currentCmd.startsWith(QLatin1String("STOR "))) {
- abortState = AbortStarted;
-#if defined(QFTPPI_DEBUG)
- qDebug("QFtpPI send: ABOR");
-#endif
- commandSocket.write("ABOR\r\n", 6);
-
- dtp.abortConnection();
- } else {
- //Deviation from RFC 959:
- //Most FTP servers do not support ABOR, or require the telnet
- //IP & synch sequence (TCP urgent data) which is not supported by QTcpSocket.
- //Following what most FTP clients do, just reset the data connection and wait for 426
- abortState = WaitForAbortToFinish;
- dtp.abortConnection();
- }
-}
-
-void QFtpPI::hostFound()
-{
- emit connectState(QFtp::Connecting);
-}
-
-void QFtpPI::connected()
-{
- state = Begin;
-#if defined(QFTPPI_DEBUG)
-// qDebug("QFtpPI state: %d [connected()]", state);
-#endif
- // try to improve performance by setting TCP_NODELAY
- commandSocket.setSocketOption(QAbstractSocket::LowDelayOption, 1);
-
- emit connectState(QFtp::Connected);
-}
-
-void QFtpPI::connectionClosed()
-{
- commandSocket.close();
- emit connectState(QFtp::Unconnected);
-}
-
-void QFtpPI::delayedCloseFinished()
-{
- emit connectState(QFtp::Unconnected);
-}
-
-void QFtpPI::error(QAbstractSocket::SocketError e)
-{
- if (e == QTcpSocket::HostNotFoundError) {
- emit connectState(QFtp::Unconnected);
- emit error(QFtp::HostNotFound,
- QFtp::tr("Host %1 not found").arg(commandSocket.peerName()));
- } else if (e == QTcpSocket::ConnectionRefusedError) {
- emit connectState(QFtp::Unconnected);
- emit error(QFtp::ConnectionRefused,
- QFtp::tr("Connection refused to host %1").arg(commandSocket.peerName()));
- } else if (e == QTcpSocket::SocketTimeoutError) {
- emit connectState(QFtp::Unconnected);
- emit error(QFtp::ConnectionRefused,
- QFtp::tr("Connection timed out to host %1").arg(commandSocket.peerName()));
- }
-}
-
-void QFtpPI::readyRead()
-{
- if (waitForDtpToClose)
- return;
-
- while (commandSocket.canReadLine()) {
- // read line with respect to line continuation
- QString line = QString::fromUtf8(commandSocket.readLine());
- if (replyText.isEmpty()) {
- if (line.length() < 3) {
- // protocol error
- return;
- }
- const int lowerLimit[3] = {1,0,0};
- const int upperLimit[3] = {5,5,9};
- for (int i=0; i<3; i++) {
- replyCode[i] = line.at(i).digitValue();
- if (replyCode[i]<lowerLimit[i] || replyCode[i]>upperLimit[i]) {
- // protocol error
- return;
- }
- }
- }
- const char count[4] = { char('0' + replyCode[0]), char('0' + replyCode[1]),
- char('0' + replyCode[2]), char(' ') };
- QString endOfMultiLine(QLatin1String(count, 4));
- QString lineCont(endOfMultiLine);
- lineCont[3] = QLatin1Char('-');
- QStringView lineLeft4 = QStringView{line}.left(4);
-
- while (lineLeft4 != endOfMultiLine) {
- if (lineLeft4 == lineCont)
- replyText += QStringView{line}.mid(4); // strip 'xyz-'
- else
- replyText += line;
- if (!commandSocket.canReadLine())
- return;
- line = QString::fromUtf8(commandSocket.readLine());
- lineLeft4 = QStringView{line}.left(4);
- }
- replyText += QStringView{line}.mid(4); // strip reply code 'xyz '
- if (replyText.endsWith(QLatin1String("\r\n")))
- replyText.chop(2);
-
- if (processReply())
- replyText = QLatin1String("");
- }
-}
-
-/*
- \internal
-
- Process a reply from the FTP server.
-
- Returns \c true if the reply was processed or false if the reply has to be
- processed at a later point.
-*/
-bool QFtpPI::processReply()
-{
-#if defined(QFTPPI_DEBUG)
-// qDebug("QFtpPI state: %d [processReply() begin]", state);
- if (replyText.length() < 400)
- qDebug("QFtpPI recv: %d %s", 100*replyCode[0]+10*replyCode[1]+replyCode[2], replyText.toLatin1().constData());
- else
- qDebug("QFtpPI recv: %d (text skipped)", 100*replyCode[0]+10*replyCode[1]+replyCode[2]);
-#endif
-
- int replyCodeInt = 100*replyCode[0] + 10*replyCode[1] + replyCode[2];
-
- // process 226 replies ("Closing Data Connection") only when the data
- // connection is really closed to avoid short reads of the DTP
- if (replyCodeInt == 226 || (replyCodeInt == 250 && currentCmd.startsWith(QLatin1String("RETR")))) {
- if (dtp.state() != QTcpSocket::UnconnectedState) {
- waitForDtpToClose = true;
- return false;
- }
- }
-
- switch (abortState) {
- case AbortStarted:
- abortState = WaitForAbortToFinish;
- break;
- case WaitForAbortToFinish:
- abortState = None;
- return true;
- default:
- break;
- }
-
- // get new state
- static const State table[5] = {
- /* 1yz 2yz 3yz 4yz 5yz */
- Waiting, Success, Idle, Failure, Failure
- };
- switch (state) {
- case Begin:
- if (replyCode[0] == 1) {
- return true;
- } else if (replyCode[0] == 2) {
- state = Idle;
- emit finished(QFtp::tr("Connected to host %1").arg(commandSocket.peerName()));
- break;
- }
- // reply codes not starting with 1 or 2 are not handled.
- return true;
- case Waiting:
- if (static_cast<signed char>(replyCode[0]) < 0 || replyCode[0] > 5)
- state = Failure;
- else
- if (replyCodeInt == 202)
- state = Failure;
- else
- state = table[replyCode[0] - 1];
- break;
- default:
- // ignore unrequested message
- return true;
- }
-#if defined(QFTPPI_DEBUG)
-// qDebug("QFtpPI state: %d [processReply() intermediate]", state);
-#endif
-
- // special actions on certain replies
- emit rawFtpReply(replyCodeInt, replyText);
- if (rawCommand) {
- rawCommand = false;
- } else if (replyCodeInt == 227) {
- // 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2)
- // rfc959 does not define this response precisely, and gives
- // both examples where the parenthesis are used, and where
- // they are missing. We need to scan for the address and host
- // info.
- QRegularExpression addrPortPattern(QLatin1String("(\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)"));
- auto addrPortMatch = addrPortPattern.match(replyText);
- if (!addrPortMatch.hasMatch()) {
-#if defined(QFTPPI_DEBUG)
- qDebug("QFtp: bad 227 response -- address and port information missing");
-#endif
- // this error should be reported
- } else {
- const QStringList lst = addrPortMatch.capturedTexts();
- QString host = lst[1] + QLatin1Char('.') + lst[2] + QLatin1Char('.') + lst[3] + QLatin1Char('.') + lst[4];
- quint16 port = (lst[5].toUInt() << 8) + lst[6].toUInt();
- waitForDtpToConnect = true;
- dtp.connectToHost(host, port);
- }
- } else if (replyCodeInt == 229) {
- // 229 Extended Passive mode OK (|||10982|)
- int portPos = replyText.indexOf(QLatin1Char('('));
- if (portPos == -1) {
-#if defined(QFTPPI_DEBUG)
- qDebug("QFtp: bad 229 response -- port information missing");
-#endif
- // this error should be reported
- } else {
- ++portPos;
- QChar delimiter = replyText.at(portPos);
- const auto epsvParameters = QStringView{replyText}.mid(portPos).split(delimiter);
-
- waitForDtpToConnect = true;
- dtp.connectToHost(commandSocket.peerAddress().toString(),
- epsvParameters.at(3).toInt());
- }
-
- } else if (replyCodeInt == 230) {
- if (currentCmd.startsWith(QLatin1String("USER ")) && pendingCommands.count()>0 &&
- pendingCommands.constFirst().startsWith(QLatin1String("PASS "))) {
- // no need to send the PASS -- we are already logged in
- pendingCommands.pop_front();
- }
- // 230 User logged in, proceed.
- emit connectState(QFtp::LoggedIn);
- } else if (replyCodeInt == 213) {
- // 213 File status.
- if (currentCmd.startsWith(QLatin1String("SIZE ")))
- dtp.setBytesTotal(replyText.simplified().toLongLong());
- } else if (replyCode[0]==1 && currentCmd.startsWith(QLatin1String("STOR "))) {
- dtp.waitForConnection();
- dtp.writeData();
- }
-
- // react on new state
- switch (state) {
- case Begin:
- // should never happen
- break;
- case Success:
- // success handling
- state = Idle;
- Q_FALLTHROUGH();
- case Idle:
- if (dtp.hasError()) {
- emit error(QFtp::UnknownError, dtp.errorMessage());
- dtp.clearError();
- }
- startNextCmd();
- break;
- case Waiting:
- // do nothing
- break;
- case Failure:
- // If the EPSV or EPRT commands fail, replace them with
- // the old PASV and PORT instead and try again.
- if (currentCmd.startsWith(QLatin1String("EPSV"))) {
- transferConnectionExtended = false;
- pendingCommands.prepend(QLatin1String("PASV\r\n"));
- } else if (currentCmd.startsWith(QLatin1String("EPRT"))) {
- transferConnectionExtended = false;
- pendingCommands.prepend(QLatin1String("PORT\r\n"));
- } else {
- emit error(QFtp::UnknownError, replyText);
- }
- if (state != Waiting) {
- state = Idle;
- startNextCmd();
- }
- break;
- }
-#if defined(QFTPPI_DEBUG)
-// qDebug("QFtpPI state: %d [processReply() end]", state);
-#endif
- return true;
-}
-
-/*
- \internal
-
- Starts next pending command. Returns \c false if there are no pending commands,
- otherwise it returns \c true.
-*/
-bool QFtpPI::startNextCmd()
-{
- if (waitForDtpToConnect)
- // don't process any new commands until we are connected
- return true;
-
-#if defined(QFTPPI_DEBUG)
- if (state != Idle)
- qDebug("QFtpPI startNextCmd: Internal error! QFtpPI called in non-Idle state %d", state);
-#endif
- if (pendingCommands.isEmpty()) {
- currentCmd.clear();
- emit finished(replyText);
- return false;
- }
- currentCmd = pendingCommands.constFirst();
-
- // PORT and PASV are edited in-place, depending on whether we
- // should try the extended transfer connection commands EPRT and
- // EPSV. The PORT command also triggers setting up a listener, and
- // the address/port arguments are edited in.
- QHostAddress address = commandSocket.localAddress();
- if (currentCmd.startsWith(QLatin1String("PORT"))) {
- if ((address.protocol() == QTcpSocket::IPv6Protocol) && transferConnectionExtended) {
- int port = dtp.setupListener(address);
- currentCmd = QLatin1String("EPRT |");
- currentCmd += (address.protocol() == QTcpSocket::IPv4Protocol) ? QLatin1Char('1') : QLatin1Char('2');
- currentCmd += QLatin1Char('|') + address.toString() + QLatin1Char('|') + QString::number(port);
- currentCmd += QLatin1Char('|');
- } else if (address.protocol() == QTcpSocket::IPv4Protocol) {
- int port = dtp.setupListener(address);
- QString portArg;
- quint32 ip = address.toIPv4Address();
- portArg += QString::number((ip & 0xff000000) >> 24);
- portArg += QLatin1Char(',') + QString::number((ip & 0xff0000) >> 16);
- portArg += QLatin1Char(',') + QString::number((ip & 0xff00) >> 8);
- portArg += QLatin1Char(',') + QString::number(ip & 0xff);
- portArg += QLatin1Char(',') + QString::number((port & 0xff00) >> 8);
- portArg += QLatin1Char(',') + QString::number(port & 0xff);
-
- currentCmd = QLatin1String("PORT ");
- currentCmd += portArg;
- } else {
- // No IPv6 connection can be set up with the PORT
- // command.
- return false;
- }
-
- currentCmd += QLatin1String("\r\n");
- } else if (currentCmd.startsWith(QLatin1String("PASV"))) {
- if ((address.protocol() == QTcpSocket::IPv6Protocol) && transferConnectionExtended)
- currentCmd = QLatin1String("EPSV\r\n");
- }
-
- pendingCommands.pop_front();
-#if defined(QFTPPI_DEBUG)
- qDebug("QFtpPI send: %s", QStringView{currentCmd}.left(currentCmd.length() - 2).toLatin1().constData());
-#endif
- state = Waiting;
- commandSocket.write(currentCmd.toUtf8());
- return true;
-}
-
-void QFtpPI::dtpConnectState(int s)
-{
- switch (s) {
- case QFtpDTP::CsClosed:
- if (waitForDtpToClose) {
- // there is an unprocessed reply
- if (processReply())
- replyText = QLatin1String("");
- else
- return;
- }
- waitForDtpToClose = false;
- readyRead();
- return;
- case QFtpDTP::CsConnected:
- waitForDtpToConnect = false;
- startNextCmd();
- return;
- case QFtpDTP::CsHostNotFound:
- case QFtpDTP::CsConnectionRefused:
- emit error(QFtp::ConnectionRefused,
- QFtp::tr("Data Connection refused"));
- startNextCmd();
- return;
- default:
- return;
- }
-}
-
-/**********************************************************************
- *
- * QFtpPrivate
- *
- *********************************************************************/
-
-QT_BEGIN_INCLUDE_NAMESPACE
-#include <private/qobject_p.h>
-QT_END_INCLUDE_NAMESPACE
-
-class QFtpPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QFtp)
-public:
-
- inline QFtpPrivate() : close_waitForStateChange(false), state(QFtp::Unconnected),
- transferMode(QFtp::Passive), error(QFtp::NoError)
- { }
-
- ~QFtpPrivate() { while (!pending.isEmpty()) delete pending.takeFirst(); }
-
- // private slots
- void _q_startNextCommand();
- void _q_piFinished(const QString&);
- void _q_piError(int, const QString&);
- void _q_piConnectState(int);
- void _q_piFtpReply(int, const QString&);
-
- int addCommand(QFtpCommand *cmd);
-
- QFtpPI pi;
- QList<QFtpCommand *> pending;
- bool close_waitForStateChange;
- QFtp::State state;
- QFtp::TransferMode transferMode;
- QFtp::Error error;
- QString errorString;
-
- QString host;
- quint16 port;
- QString proxyHost;
- quint16 proxyPort;
-};
-
-int QFtpPrivate::addCommand(QFtpCommand *cmd)
-{
- pending.append(cmd);
-
- if (pending.count() == 1) {
- // don't emit the commandStarted() signal before the ID is returned
- QTimer::singleShot(0, q_func(), SLOT(_q_startNextCommand()));
- }
- return cmd->id;
-}
-
-/**********************************************************************
- *
- * QFtp implementation
- *
- *********************************************************************/
-/*!
- \internal
- \class QFtp
- \brief The QFtp class provides an implementation of the client side of FTP protocol.
-
- \ingroup network
- \inmodule QtNetwork
-
-
- This class provides a direct interface to FTP that allows you to
- have more control over the requests. However, for new
- applications, it is recommended to use QNetworkAccessManager and
- QNetworkReply, as those classes possess a simpler, yet more
- powerful API.
-
- The class works asynchronously, so there are no blocking
- functions. If an operation cannot be executed immediately, the
- function will still return straight away and the operation will be
- scheduled for later execution. The results of scheduled operations
- are reported via signals. This approach depends on the event loop
- being in operation.
-
- The operations that can be scheduled (they are called "commands"
- in the rest of the documentation) are the following:
- connectToHost(), login(), close(), list(), cd(), get(), put(),
- remove(), mkdir(), rmdir(), rename() and rawCommand().
-
- All of these commands return a unique identifier that allows you
- to keep track of the command that is currently being executed.
- When the execution of a command starts, the commandStarted()
- signal with the command's identifier is emitted. When the command
- is finished, the commandFinished() signal is emitted with the
- command's identifier and a bool that indicates whether the command
- finished with an error.
-
- In some cases, you might want to execute a sequence of commands,
- e.g. if you want to connect and login to a FTP server. This is
- simply achieved:
-
- \snippet code/src_network_access_qftp.cpp 0
-
- In this case two FTP commands have been scheduled. When the last
- scheduled command has finished, a done() signal is emitted with
- a bool argument that tells you whether the sequence finished with
- an error.
-
- If an error occurs during the execution of one of the commands in
- a sequence of commands, all the pending commands (i.e. scheduled,
- but not yet executed commands) are cleared and no signals are
- emitted for them.
-
- Some commands, e.g. list(), emit additional signals to report
- their results.
-
- Example: If you want to download the INSTALL file from the Qt
- FTP server, you would write this:
-
- \snippet code/src_network_access_qftp.cpp 1
-
- For this example the following sequence of signals is emitted
- (with small variations, depending on network traffic, etc.):
-
- \snippet code/src_network_access_qftp.cpp 2
-
- The dataTransferProgress() signal in the above example is useful
- if you want to show a \l{QProgressBar}{progress bar} to
- inform the user about the progress of the download. The
- readyRead() signal tells you that there is data ready to be read.
- The amount of data can be queried then with the bytesAvailable()
- function and it can be read with the read() or readAll()
- function.
-
- If the login fails for the above example, the signals would look
- like this:
-
- \snippet code/src_network_access_qftp.cpp 3
-
- You can then get details about the error with the error() and
- errorString() functions.
-
- For file transfer, QFtp can use both active or passive mode, and
- it uses passive file transfer mode by default; see the
- documentation for setTransferMode() for more details about this.
-
- Call setProxy() to make QFtp connect via an FTP proxy server.
-
- The functions currentId() and currentCommand() provide more
- information about the currently executing command.
-
- The functions hasPendingCommands() and clearPendingCommands()
- allow you to query and clear the list of pending commands.
-
- If you are an experienced network programmer and want to have
- complete control you can use rawCommand() to execute arbitrary FTP
- commands.
-
- \warning The current version of QFtp doesn't fully support
- non-Unix FTP servers.
-
- \sa QNetworkAccessManager, QNetworkRequest, QNetworkReply,
- {FTP Example}
-*/
-
-
-/*!
- \internal
- Constructs a QFtp object with the given \a parent.
-*/
-QFtp::QFtp(QObject *parent)
- : QObject(*new QFtpPrivate, parent)
-{
- Q_D(QFtp);
- d->errorString = tr("Unknown error");
-
- connect(&d->pi, SIGNAL(connectState(int)),
- SLOT(_q_piConnectState(int)));
- connect(&d->pi, SIGNAL(finished(QString)),
- SLOT(_q_piFinished(QString)));
- connect(&d->pi, SIGNAL(error(int,QString)),
- SLOT(_q_piError(int,QString)));
- connect(&d->pi, SIGNAL(rawFtpReply(int,QString)),
- SLOT(_q_piFtpReply(int,QString)));
-
- connect(&d->pi.dtp, SIGNAL(readyRead()),
- SIGNAL(readyRead()));
- connect(&d->pi.dtp, SIGNAL(dataTransferProgress(qint64,qint64)),
- SIGNAL(dataTransferProgress(qint64,qint64)));
- connect(&d->pi.dtp, SIGNAL(listInfo(QUrlInfo)),
- SIGNAL(listInfo(QUrlInfo)));
-}
-
-/*!
- \internal
- \enum QFtp::State
-
- This enum defines the connection state:
-
- \value Unconnected There is no connection to the host.
- \value HostLookup A host name lookup is in progress.
- \value Connecting An attempt to connect to the host is in progress.
- \value Connected Connection to the host has been achieved.
- \value LoggedIn Connection and user login have been achieved.
- \value Closing The connection is closing down, but it is not yet
- closed. (The state will be \c Unconnected when the connection is
- closed.)
-
- \sa stateChanged(), state()
-*/
-/*!
- \internal
- \enum QFtp::TransferMode
-
- FTP works with two socket connections; one for commands and
- another for transmitting data. While the command connection is
- always initiated by the client, the second connection can be
- initiated by either the client or the server.
-
- This enum defines whether the client (Passive mode) or the server
- (Active mode) should set up the data connection.
-
- \value Passive The client connects to the server to transmit its
- data.
-
- \value Active The server connects to the client to transmit its
- data.
-*/
-/*!
- \internal
- \enum QFtp::TransferType
-
- This enum identifies the data transfer type used with get and
- put commands.
-
- \value Binary The data will be transferred in Binary mode.
-
- \value Ascii The data will be transferred in Ascii mode and new line
- characters will be converted to the local format.
-*/
-/*!
- \internal
- \enum QFtp::Error
-
- This enum identifies the error that occurred.
-
- \value NoError No error occurred.
- \value HostNotFound The host name lookup failed.
- \value ConnectionRefused The server refused the connection.
- \value NotConnected Tried to send a command, but there is no connection to
- a server.
- \value UnknownError An error other than those specified above
- occurred.
-
- \sa error()
-*/
-
-/*!
- \internal
- \enum QFtp::Command
-
- This enum is used as the return value for the currentCommand() function.
- This allows you to perform specific actions for particular
- commands, e.g. in a FTP client, you might want to clear the
- directory view when a list() command is started; in this case you
- can simply check in the slot connected to the start() signal if
- the currentCommand() is \c List.
-
- \value None No command is being executed.
- \value SetTransferMode set the \l{TransferMode}{transfer} mode.
- \value SetProxy switch proxying on or off.
- \value ConnectToHost connectToHost() is being executed.
- \value Login login() is being executed.
- \value Close close() is being executed.
- \value List list() is being executed.
- \value Cd cd() is being executed.
- \value Get get() is being executed.
- \value Put put() is being executed.
- \value Remove remove() is being executed.
- \value Mkdir mkdir() is being executed.
- \value Rmdir rmdir() is being executed.
- \value Rename rename() is being executed.
- \value RawCommand rawCommand() is being executed.
-
- \sa currentCommand()
-*/
-
-/*!
- \internal
- \fn void QFtp::stateChanged(int state)
-
- This signal is emitted when the state of the connection changes.
- The argument \a state is the new state of the connection; it is
- one of the \l State values.
-
- It is usually emitted in response to a connectToHost() or close()
- command, but it can also be emitted "spontaneously", e.g. when the
- server closes the connection unexpectedly.
-
- \sa connectToHost(), close(), state(), State
-*/
-
-/*!
- \internal
- \fn void QFtp::listInfo(const QUrlInfo &i);
-
- This signal is emitted for each directory entry the list() command
- finds. The details of the entry are stored in \a i.
-
- \sa list()
-*/
-
-/*!
- \internal
- \fn void QFtp::commandStarted(int id)
-
- This signal is emitted when processing the command identified by
- \a id starts.
-
- \sa commandFinished(), done()
-*/
-
-/*!
- \internal
- \fn void QFtp::commandFinished(int id, bool error)
-
- This signal is emitted when processing the command identified by
- \a id has finished. \a error is true if an error occurred during
- the processing; otherwise \a error is false.
-
- \sa commandStarted(), done(), error(), errorString()
-*/
-
-/*!
- \internal
- \fn void QFtp::done(bool error)
-
- This signal is emitted when the last pending command has finished;
- (it is emitted after the last command's commandFinished() signal).
- \a error is true if an error occurred during the processing;
- otherwise \a error is false.
-
- \sa commandFinished(), error(), errorString()
-*/
-
-/*!
- \internal
- \fn void QFtp::readyRead()
-
- This signal is emitted in response to a get() command when there
- is new data to read.
-
- If you specify a device as the second argument in the get()
- command, this signal is \e not emitted; instead the data is
- written directly to the device.
-
- You can read the data with the readAll() or read() functions.
-
- This signal is useful if you want to process the data in chunks as
- soon as it becomes available. If you are only interested in the
- complete data, just connect to the commandFinished() signal and
- read the data then instead.
-
- \sa get(), read(), readAll(), bytesAvailable()
-*/
-
-/*!
- \internal
- \fn void QFtp::dataTransferProgress(qint64 done, qint64 total)
-
- This signal is emitted in response to a get() or put() request to
- indicate the current progress of the download or upload.
-
- \a done is the amount of data that has already been transferred
- and \a total is the total amount of data to be read or written. It
- is possible that the QFtp class is not able to determine the total
- amount of data that should be transferred, in which case \a total
- is 0. (If you connect this signal to a QProgressBar, the progress
- bar shows a busy indicator if the total is 0).
-
- \warning \a done and \a total are not necessarily the size in
- bytes, since for large files these values might need to be
- "scaled" to avoid overflow.
-
- \sa get(), put(), QProgressBar
-*/
-
-/*!
- \internal
- \fn void QFtp::rawCommandReply(int replyCode, const QString &detail);
-
- This signal is emitted in response to the rawCommand() function.
- \a replyCode is the 3 digit reply code and \a detail is the text
- that follows the reply code.
-
- \sa rawCommand()
-*/
-
-/*!
- \internal
- Connects to the FTP server \a host using port \a port.
-
- The stateChanged() signal is emitted when the state of the
- connecting process changes, e.g. to \c HostLookup, then \c
- Connecting, then \c Connected.
-
- The function does not block and returns immediately. The command
- is scheduled, and its execution is performed asynchronously. The
- function returns a unique identifier which is passed by
- commandStarted() and commandFinished().
-
- When the command is started the commandStarted() signal is
- emitted. When it is finished the commandFinished() signal is
- emitted.
-
- \sa stateChanged(), commandStarted(), commandFinished()
-*/
-int QFtp::connectToHost(const QString &host, quint16 port)
-{
- QStringList cmds;
- cmds << host;
- cmds << QString::number((uint)port);
- int id = d_func()->addCommand(new QFtpCommand(ConnectToHost, cmds));
- d_func()->pi.transferConnectionExtended = true;
- return id;
-}
-
-/*!
- \internal
- Logs in to the FTP server with the username \a user and the
- password \a password.
-
- The stateChanged() signal is emitted when the state of the
- connecting process changes, e.g. to \c LoggedIn.
-
- The function does not block and returns immediately. The command
- is scheduled, and its execution is performed asynchronously. The
- function returns a unique identifier which is passed by
- commandStarted() and commandFinished().
-
- When the command is started the commandStarted() signal is
- emitted. When it is finished the commandFinished() signal is
- emitted.
-
- \sa commandStarted(), commandFinished()
-*/
-int QFtp::login(const QString &user, const QString &password)
-{
- QStringList cmds;
-
- if (user.isNull() || user.compare(QLatin1String("anonymous"), Qt::CaseInsensitive) == 0) {
- cmds << (QLatin1String("USER ") + (user.isNull() ? QLatin1String("anonymous") : user) + QLatin1String("\r\n"));
- cmds << (QLatin1String("PASS ") + (password.isNull() ? QLatin1String("anonymous@") : password) + QLatin1String("\r\n"));
- } else {
- cmds << (QLatin1String("USER ") + user + QLatin1String("\r\n"));
- if (!password.isNull())
- cmds << (QLatin1String("PASS ") + password + QLatin1String("\r\n"));
- }
-
- return d_func()->addCommand(new QFtpCommand(Login, cmds));
-}
-
-/*!
- \internal
- Closes the connection to the FTP server.
-
- The stateChanged() signal is emitted when the state of the
- connecting process changes, e.g. to \c Closing, then \c
- Unconnected.
-
- The function does not block and returns immediately. The command
- is scheduled, and its execution is performed asynchronously. The
- function returns a unique identifier which is passed by
- commandStarted() and commandFinished().
-
- When the command is started the commandStarted() signal is
- emitted. When it is finished the commandFinished() signal is
- emitted.
-
- \sa stateChanged(), commandStarted(), commandFinished()
-*/
-int QFtp::close()
-{
- return d_func()->addCommand(new QFtpCommand(Close, QStringList(QLatin1String("QUIT\r\n"))));
-}
-
-/*!
- \internal
- Sets the current FTP transfer mode to \a mode. The default is QFtp::Passive.
-
- \sa QFtp::TransferMode
-*/
-int QFtp::setTransferMode(TransferMode mode)
-{
- int id = d_func()->addCommand(new QFtpCommand(SetTransferMode, QStringList()));
- d_func()->pi.transferConnectionExtended = true;
- d_func()->transferMode = mode;
- return id;
-}
-
-/*!
- \internal
- Enables use of the FTP proxy on host \a host and port \a
- port. Calling this function with \a host empty disables proxying.
-
- QFtp does not support FTP-over-HTTP proxy servers. Use
- QNetworkAccessManager for this.
-*/
-int QFtp::setProxy(const QString &host, quint16 port)
-{
- QStringList args;
- args << host << QString::number(port);
- return d_func()->addCommand(new QFtpCommand(SetProxy, args));
-}
-
-/*!
- \internal
- Lists the contents of directory \a dir on the FTP server. If \a
- dir is empty, it lists the contents of the current directory.
-
- The listInfo() signal is emitted for each directory entry found.
-
- The function does not block and returns immediately. The command
- is scheduled, and its execution is performed asynchronously. The
- function returns a unique identifier which is passed by
- commandStarted() and commandFinished().
-
- When the command is started the commandStarted() signal is
- emitted. When it is finished the commandFinished() signal is
- emitted.
-
- \sa listInfo(), commandStarted(), commandFinished()
-*/
-int QFtp::list(const QString &dir)
-{
- QStringList cmds;
- cmds << QLatin1String("TYPE A\r\n");
- cmds << QLatin1String(d_func()->transferMode == Passive ? "PASV\r\n" : "PORT\r\n");
- if (dir.isEmpty())
- cmds << QLatin1String("LIST\r\n");
- else
- cmds << (QLatin1String("LIST ") + dir + QLatin1String("\r\n"));
- return d_func()->addCommand(new QFtpCommand(List, cmds));
-}
-
-/*!
- \internal
- Changes the working directory of the server to \a dir.
-
- The function does not block and returns immediately. The command
- is scheduled, and its execution is performed asynchronously. The
- function returns a unique identifier which is passed by
- commandStarted() and commandFinished().
-
- When the command is started the commandStarted() signal is
- emitted. When it is finished the commandFinished() signal is
- emitted.
-
- \sa commandStarted(), commandFinished()
-*/
-int QFtp::cd(const QString &dir)
-{
- return d_func()->addCommand(new QFtpCommand(Cd, QStringList(QLatin1String("CWD ") + dir + QLatin1String("\r\n"))));
-}
-
-/*!
- \internal
- Downloads the file \a file from the server.
-
- If \a dev is \nullptr, then the readyRead() signal is emitted when there
- is data available to read. You can then read the data with the
- read() or readAll() functions.
-
- If \a dev is not \nullptr, the data is written directly to the device
- \a dev. Make sure that the \a dev pointer is valid for the duration
- of the operation (it is safe to delete it when the
- commandFinished() signal is emitted). In this case the readyRead()
- signal is \e not emitted and you cannot read data with the
- read() or readAll() functions.
-
- If you don't read the data immediately it becomes available, i.e.
- when the readyRead() signal is emitted, it is still available
- until the next command is started.
-
- For example, if you want to present the data to the user as soon
- as there is something available, connect to the readyRead() signal
- and read the data immediately. On the other hand, if you only want
- to work with the complete data, you can connect to the
- commandFinished() signal and read the data when the get() command
- is finished.
-
- The data is transferred as Binary or Ascii depending on the value
- of \a type.
-
- The function does not block and returns immediately. The command
- is scheduled, and its execution is performed asynchronously. The
- function returns a unique identifier which is passed by
- commandStarted() and commandFinished().
-
- When the command is started the commandStarted() signal is
- emitted. When it is finished the commandFinished() signal is
- emitted.
-
- \sa readyRead(), dataTransferProgress(), commandStarted(),
- commandFinished()
-*/
-int QFtp::get(const QString &file, QIODevice *dev, TransferType type)
-{
- QStringList cmds;
- if (type == Binary)
- cmds << QLatin1String("TYPE I\r\n");
- else
- cmds << QLatin1String("TYPE A\r\n");
- cmds << QLatin1String("SIZE ") + file + QLatin1String("\r\n");
- cmds << QLatin1String(d_func()->transferMode == Passive ? "PASV\r\n" : "PORT\r\n");
- cmds << QLatin1String("RETR ") + file + QLatin1String("\r\n");
- return d_func()->addCommand(new QFtpCommand(Get, cmds, dev));
-}
-
-/*!
- \internal
- \overload
-
- Writes a copy of the given \a data to the file called \a file on
- the server. The progress of the upload is reported by the
- dataTransferProgress() signal.
-
- The data is transferred as Binary or Ascii depending on the value
- of \a type.
-
- The function does not block and returns immediately. The command
- is scheduled, and its execution is performed asynchronously. The
- function returns a unique identifier which is passed by
- commandStarted() and commandFinished().
-
- When the command is started the commandStarted() signal is
- emitted. When it is finished the commandFinished() signal is
- emitted.
-
- Since this function takes a copy of the \a data, you can discard
- your own copy when this function returns.
-
- \sa dataTransferProgress(), commandStarted(), commandFinished()
-*/
-int QFtp::put(const QByteArray &data, const QString &file, TransferType type)
-{
- QStringList cmds;
- if (type == Binary)
- cmds << QLatin1String("TYPE I\r\n");
- else
- cmds << QLatin1String("TYPE A\r\n");
- cmds << QLatin1String(d_func()->transferMode == Passive ? "PASV\r\n" : "PORT\r\n");
- cmds << QLatin1String("ALLO ") + QString::number(data.size()) + QLatin1String("\r\n");
- cmds << QLatin1String("STOR ") + file + QLatin1String("\r\n");
- return d_func()->addCommand(new QFtpCommand(Put, cmds, data));
-}
-
-/*!
- \internal
- Reads the data from the IO device \a dev, and writes it to the
- file called \a file on the server. The data is read in chunks from
- the IO device, so this overload allows you to transmit large
- amounts of data without the need to read all the data into memory
- at once.
-
- The data is transferred as Binary or Ascii depending on the value
- of \a type.
-
- Make sure that the \a dev pointer is valid for the duration of the
- operation (it is safe to delete it when the commandFinished() is
- emitted).
-*/
-int QFtp::put(QIODevice *dev, const QString &file, TransferType type)
-{
- QStringList cmds;
- if (type == Binary)
- cmds << QLatin1String("TYPE I\r\n");
- else
- cmds << QLatin1String("TYPE A\r\n");
- cmds << QLatin1String(d_func()->transferMode == Passive ? "PASV\r\n" : "PORT\r\n");
- if (!dev->isSequential())
- cmds << QLatin1String("ALLO ") + QString::number(dev->size()) + QLatin1String("\r\n");
- cmds << QLatin1String("STOR ") + file + QLatin1String("\r\n");
- return d_func()->addCommand(new QFtpCommand(Put, cmds, dev));
-}
-
-/*!
- \internal
- Deletes the file called \a file from the server.
-
- The function does not block and returns immediately. The command
- is scheduled, and its execution is performed asynchronously. The
- function returns a unique identifier which is passed by
- commandStarted() and commandFinished().
-
- When the command is started the commandStarted() signal is
- emitted. When it is finished the commandFinished() signal is
- emitted.
-
- \sa commandStarted(), commandFinished()
-*/
-int QFtp::remove(const QString &file)
-{
- return d_func()->addCommand(new QFtpCommand(Remove, QStringList(QLatin1String("DELE ") + file + QLatin1String("\r\n"))));
-}
-
-/*!
- \internal
- Creates a directory called \a dir on the server.
-
- The function does not block and returns immediately. The command
- is scheduled, and its execution is performed asynchronously. The
- function returns a unique identifier which is passed by
- commandStarted() and commandFinished().
-
- When the command is started the commandStarted() signal is
- emitted. When it is finished the commandFinished() signal is
- emitted.
-
- \sa commandStarted(), commandFinished()
-*/
-int QFtp::mkdir(const QString &dir)
-{
- return d_func()->addCommand(new QFtpCommand(Mkdir, QStringList(QLatin1String("MKD ") + dir + QLatin1String("\r\n"))));
-}
-
-/*!
- \internal
- Removes the directory called \a dir from the server.
-
- The function does not block and returns immediately. The command
- is scheduled, and its execution is performed asynchronously. The
- function returns a unique identifier which is passed by
- commandStarted() and commandFinished().
-
- When the command is started the commandStarted() signal is
- emitted. When it is finished the commandFinished() signal is
- emitted.
-
- \sa commandStarted(), commandFinished()
-*/
-int QFtp::rmdir(const QString &dir)
-{
- return d_func()->addCommand(new QFtpCommand(Rmdir, QStringList(QLatin1String("RMD ") + dir + QLatin1String("\r\n"))));
-}
-
-/*!
- \internal
- Renames the file called \a oldname to \a newname on the server.
-
- The function does not block and returns immediately. The command
- is scheduled, and its execution is performed asynchronously. The
- function returns a unique identifier which is passed by
- commandStarted() and commandFinished().
-
- When the command is started the commandStarted() signal is
- emitted. When it is finished the commandFinished() signal is
- emitted.
-
- \sa commandStarted(), commandFinished()
-*/
-int QFtp::rename(const QString &oldname, const QString &newname)
-{
- QStringList cmds;
- cmds << QLatin1String("RNFR ") + oldname + QLatin1String("\r\n");
- cmds << QLatin1String("RNTO ") + newname + QLatin1String("\r\n");
- return d_func()->addCommand(new QFtpCommand(Rename, cmds));
-}
-
-/*!
- \internal
- Sends the raw FTP command \a command to the FTP server. This is
- useful for low-level FTP access. If the operation you wish to
- perform has an equivalent QFtp function, we recommend using the
- function instead of raw FTP commands since the functions are
- easier and safer.
-
- The function does not block and returns immediately. The command
- is scheduled, and its execution is performed asynchronously. The
- function returns a unique identifier which is passed by
- commandStarted() and commandFinished().
-
- When the command is started the commandStarted() signal is
- emitted. When it is finished the commandFinished() signal is
- emitted.
-
- \sa rawCommandReply(), commandStarted(), commandFinished()
-*/
-int QFtp::rawCommand(const QString &command)
-{
- const QString cmd = QStringView{command}.trimmed() + QLatin1String("\r\n");
- return d_func()->addCommand(new QFtpCommand(RawCommand, QStringList(cmd)));
-}
-
-/*!
- \internal
- Returns the number of bytes that can be read from the data socket
- at the moment.
-
- \sa get(), readyRead(), read(), readAll()
-*/
-qint64 QFtp::bytesAvailable() const
-{
- return d_func()->pi.dtp.bytesAvailable();
-}
-
-/*!
- \internal
- Reads \a maxlen bytes from the data socket into \a data and
- returns the number of bytes read. Returns -1 if an error occurred.
-
- \sa get(), readyRead(), bytesAvailable(), readAll()
-*/
-qint64 QFtp::read(char *data, qint64 maxlen)
-{
- return d_func()->pi.dtp.read(data, maxlen);
-}
-
-/*!
- \internal
- Reads all the bytes available from the data socket and returns
- them.
-
- \sa get(), readyRead(), bytesAvailable(), read()
-*/
-QByteArray QFtp::readAll()
-{
- return d_func()->pi.dtp.readAll();
-}
-
-/*!
- \internal
- Aborts the current command and deletes all scheduled commands.
-
- If there is an unfinished command (i.e. a command for which the
- commandStarted() signal has been emitted, but for which the
- commandFinished() signal has not been emitted), this function
- sends an \c ABORT command to the server. When the server replies
- that the command is aborted, the commandFinished() signal with the
- \c error argument set to \c true is emitted for the command. Due
- to timing issues, it is possible that the command had already
- finished before the abort request reached the server, in which
- case, the commandFinished() signal is emitted with the \c error
- argument set to \c false.
-
- For all other commands that are affected by the abort(), no
- signals are emitted.
-
- If you don't start further FTP commands directly after the
- abort(), there won't be any scheduled commands and the done()
- signal is emitted.
-
- \warning Some FTP servers, for example the BSD FTP daemon (version
- 0.3), wrongly return a positive reply even when an abort has
- occurred. For these servers the commandFinished() signal has its
- error flag set to \c false, even though the command did not
- complete successfully.
-
- \sa clearPendingCommands()
-*/
-void QFtp::abort()
-{
- if (d_func()->pending.isEmpty())
- return;
-
- clearPendingCommands();
- d_func()->pi.abort();
-}
-
-/*!
- \internal
- Clears the last error.
-
- \sa currentCommand()
-*/
-void QFtp::clearError()
-{
- d_func()->error = NoError;
-}
-
-/*!
- \internal
- Returns the identifier of the FTP command that is being executed
- or 0 if there is no command being executed.
-
- \sa currentCommand()
-*/
-int QFtp::currentId() const
-{
- if (d_func()->pending.isEmpty())
- return 0;
- return d_func()->pending.first()->id;
-}
-
-/*!
- \internal
- Returns the command type of the FTP command being executed or \c
- None if there is no command being executed.
-
- \sa currentId()
-*/
-QFtp::Command QFtp::currentCommand() const
-{
- if (d_func()->pending.isEmpty())
- return None;
- return d_func()->pending.first()->command;
-}
-
-/*!
- \internal
- Returns the QIODevice pointer that is used by the FTP command to read data
- from or store data to. If there is no current FTP command being executed or
- if the command does not use an IO device, this function returns \nullptr.
-
- This function can be used to delete the QIODevice in the slot connected to
- the commandFinished() signal.
-
- \sa get(), put()
-*/
-QIODevice* QFtp::currentDevice() const
-{
- if (d_func()->pending.isEmpty())
- return nullptr;
- QFtpCommand *c = d_func()->pending.first();
- if (c->is_ba)
- return nullptr;
- return c->data.dev;
-}
-
-/*!
- \internal
- Returns \c true if there are any commands scheduled that have not yet
- been executed; otherwise returns \c false.
-
- The command that is being executed is \e not considered as a
- scheduled command.
-
- \sa clearPendingCommands(), currentId(), currentCommand()
-*/
-bool QFtp::hasPendingCommands() const
-{
- return d_func()->pending.count() > 1;
-}
-
-/*!
- \internal
- Deletes all pending commands from the list of scheduled commands.
- This does not affect the command that is being executed. If you
- want to stop this as well, use abort().
-
- \sa hasPendingCommands(), abort()
-*/
-void QFtp::clearPendingCommands()
-{
- // delete all entires except the first one
- while (d_func()->pending.count() > 1)
- delete d_func()->pending.takeLast();
-}
-
-/*!
- \internal
- Returns the current state of the object. When the state changes,
- the stateChanged() signal is emitted.
-
- \sa State, stateChanged()
-*/
-QFtp::State QFtp::state() const
-{
- return d_func()->state;
-}
-
-/*!
- \internal
- Returns the last error that occurred. This is useful to find out
- what went wrong when receiving a commandFinished() or a done()
- signal with the \c error argument set to \c true.
-
- If you start a new command, the error status is reset to \c NoError.
-*/
-QFtp::Error QFtp::error() const
-{
- return d_func()->error;
-}
-
-/*!
- \internal
- Returns a human-readable description of the last error that
- occurred. This is useful for presenting a error message to the
- user when receiving a commandFinished() or a done() signal with
- the \c error argument set to \c true.
-
- The error string is often (but not always) the reply from the
- server, so it is not always possible to translate the string. If
- the message comes from Qt, the string has already passed through
- tr().
-*/
-QString QFtp::errorString() const
-{
- return d_func()->errorString;
-}
-
-/*! \internal
-*/
-void QFtpPrivate::_q_startNextCommand()
-{
- Q_Q(QFtp);
- if (pending.isEmpty())
- return;
- QFtpCommand *c = pending.constFirst();
-
- error = QFtp::NoError;
- errorString = QT_TRANSLATE_NOOP(QFtp, QLatin1String("Unknown error"));
-
- if (q->bytesAvailable())
- q->readAll(); // clear the data
- emit q->commandStarted(c->id);
-
- // Proxy support, replace the Login argument in place, then fall
- // through.
- if (c->command == QFtp::Login && !proxyHost.isEmpty()) {
- QString loginString;
- loginString += QStringView{c->rawCmds.constFirst()}.trimmed() + QLatin1Char('@') + host;
- if (port && port != 21)
- loginString += QLatin1Char(':') + QString::number(port);
- loginString += QLatin1String("\r\n");
- c->rawCmds[0] = loginString;
- }
-
- if (c->command == QFtp::SetTransferMode) {
- _q_piFinished(QLatin1String("Transfer mode set"));
- } else if (c->command == QFtp::SetProxy) {
- proxyHost = c->rawCmds.at(0);
- proxyPort = c->rawCmds.at(1).toUInt();
- c->rawCmds.clear();
- _q_piFinished(QLatin1String("Proxy set to ") + proxyHost + QLatin1Char(':') + QString::number(proxyPort));
- } else if (c->command == QFtp::ConnectToHost) {
- if (!proxyHost.isEmpty()) {
- host = c->rawCmds.at(0);
- port = c->rawCmds.at(1).toUInt();
- pi.connectToHost(proxyHost, proxyPort);
- } else {
- pi.connectToHost(c->rawCmds.at(0), c->rawCmds.at(1).toUInt());
- }
- } else {
- if (c->command == QFtp::Put) {
- if (c->is_ba) {
- pi.dtp.setData(c->data.ba);
- pi.dtp.setBytesTotal(c->data.ba->size());
- } else if (c->data.dev && (c->data.dev->isOpen() || c->data.dev->open(QIODevice::ReadOnly))) {
- pi.dtp.setDevice(c->data.dev);
- if (c->data.dev->isSequential()) {
- pi.dtp.setBytesTotal(0);
- pi.dtp.connect(c->data.dev, SIGNAL(readyRead()), SLOT(dataReadyRead()));
- pi.dtp.connect(c->data.dev, SIGNAL(readChannelFinished()), SLOT(dataReadyRead()));
- } else {
- pi.dtp.setBytesTotal(c->data.dev->size());
- }
- }
- } else if (c->command == QFtp::Get) {
- if (!c->is_ba && c->data.dev) {
- pi.dtp.setDevice(c->data.dev);
- }
- } else if (c->command == QFtp::Close) {
- state = QFtp::Closing;
- emit q->stateChanged(state);
- }
- pi.sendCommands(c->rawCmds);
- }
-}
-
-/*! \internal
-*/
-void QFtpPrivate::_q_piFinished(const QString&)
-{
- if (pending.isEmpty())
- return;
- QFtpCommand *c = pending.constFirst();
-
- if (c->command == QFtp::Close) {
- // The order of in which the slots are called is arbitrary, so
- // disconnect the SIGNAL-SIGNAL temporary to make sure that we
- // don't get the commandFinished() signal before the stateChanged()
- // signal.
- if (state != QFtp::Unconnected) {
- close_waitForStateChange = true;
- return;
- }
- }
- emit q_func()->commandFinished(c->id, false);
- pending.removeFirst();
-
- delete c;
-
- if (pending.isEmpty()) {
- emit q_func()->done(false);
- } else {
- _q_startNextCommand();
- }
-}
-
-/*! \internal
-*/
-void QFtpPrivate::_q_piError(int errorCode, const QString &text)
-{
- Q_Q(QFtp);
-
- if (pending.isEmpty()) {
- qWarning("QFtpPrivate::_q_piError was called without pending command!");
- return;
- }
-
- QFtpCommand *c = pending.constFirst();
-
- // non-fatal errors
- if (c->command == QFtp::Get && pi.currentCommand().startsWith(QLatin1String("SIZE "))) {
- pi.dtp.setBytesTotal(0);
- return;
- } else if (c->command==QFtp::Put && pi.currentCommand().startsWith(QLatin1String("ALLO "))) {
- return;
- }
-
- error = QFtp::Error(errorCode);
- switch (q->currentCommand()) {
- case QFtp::ConnectToHost:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Connecting to host failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Login:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Login failed:\n%1"))
- .arg(text);
- break;
- case QFtp::List:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Listing directory failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Cd:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Changing directory failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Get:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Downloading file failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Put:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Uploading file failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Remove:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Removing file failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Mkdir:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Creating directory failed:\n%1"))
- .arg(text);
- break;
- case QFtp::Rmdir:
- errorString = QString::fromLatin1(QT_TRANSLATE_NOOP("QFtp", "Removing directory failed:\n%1"))
- .arg(text);
- break;
- default:
- errorString = text;
- break;
- }
-
- pi.clearPendingCommands();
- q->clearPendingCommands();
- emit q->commandFinished(c->id, true);
-
- pending.removeFirst();
- delete c;
- if (pending.isEmpty())
- emit q->done(true);
- else
- _q_startNextCommand();
-}
-
-/*! \internal
-*/
-void QFtpPrivate::_q_piConnectState(int connectState)
-{
- state = QFtp::State(connectState);
- emit q_func()->stateChanged(state);
- if (close_waitForStateChange) {
- close_waitForStateChange = false;
- _q_piFinished(QLatin1String(QT_TRANSLATE_NOOP("QFtp", "Connection closed")));
- }
-}
-
-/*! \internal
-*/
-void QFtpPrivate::_q_piFtpReply(int code, const QString &text)
-{
- if (q_func()->currentCommand() == QFtp::RawCommand) {
- pi.rawCommand = true;
- emit q_func()->rawCommandReply(code, text);
- }
-}
-
-/*!
- \internal
- Destructor.
-*/
-QFtp::~QFtp()
-{
- abort();
- close();
-}
-
-QT_END_NAMESPACE
-
-#include "qftp.moc"
-
-#include "moc_qftp_p.cpp"
diff --git a/src/network/access/qftp_p.h b/src/network/access/qftp_p.h
deleted file mode 100644
index a55429933b..0000000000
--- a/src/network/access/qftp_p.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of the Network Access API. This header file may change from
-// version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#ifndef QFTP_P_H
-#define QFTP_P_H
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include <QtCore/qstring.h>
-#include <private/qurlinfo_p.h>
-#include <QtCore/qobject.h>
-
-QT_REQUIRE_CONFIG(ftp);
-
-QT_BEGIN_NAMESPACE
-
-class QFtpPrivate;
-
-class Q_AUTOTEST_EXPORT QFtp : public QObject
-{
- Q_OBJECT
-
-public:
- explicit QFtp(QObject *parent = nullptr);
- virtual ~QFtp();
-
- enum State {
- Unconnected,
- HostLookup,
- Connecting,
- Connected,
- LoggedIn,
- Closing
- };
- enum Error {
- NoError,
- UnknownError,
- HostNotFound,
- ConnectionRefused,
- NotConnected
- };
- enum Command {
- None,
- SetTransferMode,
- SetProxy,
- ConnectToHost,
- Login,
- Close,
- List,
- Cd,
- Get,
- Put,
- Remove,
- Mkdir,
- Rmdir,
- Rename,
- RawCommand
- };
- enum TransferMode {
- Active,
- Passive
- };
- enum TransferType {
- Binary,
- Ascii
- };
-
- int setProxy(const QString &host, quint16 port);
- int connectToHost(const QString &host, quint16 port=21);
- int login(const QString &user = QString(), const QString &password = QString());
- int close();
- int setTransferMode(TransferMode mode);
- int list(const QString &dir = QString());
- int cd(const QString &dir);
- int get(const QString &file, QIODevice *dev=nullptr, TransferType type = Binary);
- int put(const QByteArray &data, const QString &file, TransferType type = Binary);
- int put(QIODevice *dev, const QString &file, TransferType type = Binary);
- int remove(const QString &file);
- int mkdir(const QString &dir);
- int rmdir(const QString &dir);
- int rename(const QString &oldname, const QString &newname);
-
- int rawCommand(const QString &command);
-
- qint64 bytesAvailable() const;
- qint64 read(char *data, qint64 maxlen);
- QByteArray readAll();
-
- int currentId() const;
- QIODevice* currentDevice() const;
- Command currentCommand() const;
- bool hasPendingCommands() const;
- void clearPendingCommands();
-
- State state() const;
-
- Error error() const;
- QString errorString() const;
-
-public Q_SLOTS:
- void abort();
-
-Q_SIGNALS:
- void stateChanged(int);
- void listInfo(const QUrlInfo&);
- void readyRead();
- void dataTransferProgress(qint64, qint64);
- void rawCommandReply(int, const QString&);
-
- void commandStarted(int);
- void commandFinished(int, bool);
- void done(bool);
-
-protected:
- void clearError();
-
-private:
- Q_DISABLE_COPY_MOVE(QFtp)
- Q_DECLARE_PRIVATE(QFtp)
-
- Q_PRIVATE_SLOT(d_func(), void _q_startNextCommand())
- Q_PRIVATE_SLOT(d_func(), void _q_piFinished(const QString&))
- Q_PRIVATE_SLOT(d_func(), void _q_piError(int, const QString&))
- Q_PRIVATE_SLOT(d_func(), void _q_piConnectState(int))
- Q_PRIVATE_SLOT(d_func(), void _q_piFtpReply(int, const QString&))
-};
-
-QT_END_NAMESPACE
-
-#endif // QFTP_P_H
diff --git a/src/network/access/qnetworkaccesscachebackend.cpp b/src/network/access/qnetworkaccesscachebackend.cpp
index 4986b36ab1..1a4ef27dd6 100644
--- a/src/network/access/qnetworkaccesscachebackend.cpp
+++ b/src/network/access/qnetworkaccesscachebackend.cpp
@@ -42,9 +42,6 @@
#include "qnetworkaccesscachebackend_p.h"
#include "qabstractnetworkcache.h"
#include "qfileinfo.h"
-#if QT_CONFIG(ftp)
-#include "qurlinfo_p.h"
-#endif
#include "qdir.h"
#include "qcoreapplication.h"
diff --git a/src/network/access/qnetworkaccessfilebackend.cpp b/src/network/access/qnetworkaccessfilebackend.cpp
index 507417f86c..046a16162a 100644
--- a/src/network/access/qnetworkaccessfilebackend.cpp
+++ b/src/network/access/qnetworkaccessfilebackend.cpp
@@ -39,9 +39,6 @@
#include "qnetworkaccessfilebackend_p.h"
#include "qfileinfo.h"
-#if QT_CONFIG(ftp)
-#include "qurlinfo_p.h"
-#endif
#include "qdir.h"
#include "private/qnoncontiguousbytedevice_p.h"
diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp
deleted file mode 100644
index 7c353b5c47..0000000000
--- a/src/network/access/qnetworkaccessftpbackend.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qnetworkaccessftpbackend_p.h"
-#include "qnetworkaccessmanager_p.h"
-#include "QtNetwork/qauthenticator.h"
-#include "private/qnoncontiguousbytedevice_p.h"
-#include <QStringList>
-
-QT_BEGIN_NAMESPACE
-
-enum {
- DefaultFtpPort = 21
-};
-
-static QByteArray makeCacheKey(const QUrl &url)
-{
- QUrl copy = url;
- copy.setPort(url.port(DefaultFtpPort));
- return "ftp-connection:" +
- copy.toEncoded(QUrl::RemovePassword | QUrl::RemovePath | QUrl::RemoveQuery |
- QUrl::RemoveFragment);
-}
-
-QStringList QNetworkAccessFtpBackendFactory::supportedSchemes() const
-{
- return QStringList(QStringLiteral("ftp"));
-}
-
-QNetworkAccessBackend *
-QNetworkAccessFtpBackendFactory::create(QNetworkAccessManager::Operation op,
- const QNetworkRequest &request) const
-{
- // is it an operation we know of?
- switch (op) {
- case QNetworkAccessManager::GetOperation:
- case QNetworkAccessManager::PutOperation:
- break;
-
- default:
- // no, we can't handle this operation
- return nullptr;
- }
-
- QUrl url = request.url();
- if (url.scheme().compare(QLatin1String("ftp"), Qt::CaseInsensitive) == 0)
- return new QNetworkAccessFtpBackend;
- return nullptr;
-}
-
-class QNetworkAccessCachedFtpConnection: public QFtp, public QNetworkAccessCache::CacheableObject
-{
- // Q_OBJECT
-public:
- QNetworkAccessCachedFtpConnection()
- {
- setExpires(true);
- setShareable(false);
- }
-
- void dispose() override
- {
- connect(this, SIGNAL(done(bool)), this, SLOT(deleteLater()));
- close();
- }
-
- using QFtp::clearError;
-};
-
-QNetworkAccessFtpBackend::QNetworkAccessFtpBackend()
- : ftp(nullptr), uploadDevice(nullptr), totalBytes(0), helpId(-1), sizeId(-1), mdtmId(-1), pwdId(-1),
- supportsSize(false), supportsMdtm(false), supportsPwd(false), state(Idle)
-{
-}
-
-QNetworkAccessFtpBackend::~QNetworkAccessFtpBackend()
-{
- //if backend destroyed while in use, then abort (this is the code path from QNetworkReply::abort)
- if (ftp && state != Disconnecting)
- ftp->abort();
- disconnectFromFtp(RemoveCachedConnection);
-}
-
-void QNetworkAccessFtpBackend::open()
-{
-#ifndef QT_NO_NETWORKPROXY
- QNetworkProxy proxy;
- const auto proxies = proxyList();
- for (const QNetworkProxy &p : proxies) {
- // use the first FTP proxy
- // or no proxy at all
- if (p.type() == QNetworkProxy::FtpCachingProxy
- || p.type() == QNetworkProxy::NoProxy) {
- proxy = p;
- break;
- }
- }
-
- // did we find an FTP proxy or a NoProxy?
- if (proxy.type() == QNetworkProxy::DefaultProxy) {
- // unsuitable proxies
- error(QNetworkReply::ProxyNotFoundError,
- tr("No suitable proxy found"));
- finished();
- return;
- }
-
-#endif
-
- QUrl url = this->url();
- if (url.path().isEmpty()) {
- url.setPath(QLatin1String("/"));
- setUrl(url);
- }
- if (url.path().endsWith(QLatin1Char('/'))) {
- error(QNetworkReply::ContentOperationNotPermittedError,
- tr("Cannot open %1: is a directory").arg(url.toString()));
- finished();
- return;
- }
- state = LoggingIn;
-
- QNetworkAccessCache* objectCache = QNetworkAccessManagerPrivate::getObjectCache(this);
- QByteArray cacheKey = makeCacheKey(url);
- if (!objectCache->requestEntry(cacheKey, this,
- SLOT(ftpConnectionReady(QNetworkAccessCache::CacheableObject*)))) {
- ftp = new QNetworkAccessCachedFtpConnection;
-#ifndef QT_NO_NETWORKPROXY
- if (proxy.type() == QNetworkProxy::FtpCachingProxy)
- ftp->setProxy(proxy.hostName(), proxy.port());
-#endif
- ftp->connectToHost(url.host(), url.port(DefaultFtpPort));
- ftp->login(url.userName(), url.password());
-
- objectCache->addEntry(cacheKey, ftp);
- ftpConnectionReady(ftp);
- }
-
- // Put operation
- if (operation() == QNetworkAccessManager::PutOperation) {
- uploadDevice = QNonContiguousByteDeviceFactory::wrap(createUploadByteDevice());
- uploadDevice->setParent(this);
- }
-}
-
-void QNetworkAccessFtpBackend::closeDownstreamChannel()
-{
- state = Disconnecting;
- if (operation() == QNetworkAccessManager::GetOperation)
- ftp->abort();
-}
-
-void QNetworkAccessFtpBackend::downstreamReadyWrite()
-{
- if (state == Transferring && ftp && ftp->bytesAvailable())
- ftpReadyRead();
-}
-
-void QNetworkAccessFtpBackend::ftpConnectionReady(QNetworkAccessCache::CacheableObject *o)
-{
- ftp = static_cast<QNetworkAccessCachedFtpConnection *>(o);
- connect(ftp, SIGNAL(done(bool)), SLOT(ftpDone()));
- connect(ftp, SIGNAL(rawCommandReply(int,QString)), SLOT(ftpRawCommandReply(int,QString)));
- connect(ftp, SIGNAL(readyRead()), SLOT(ftpReadyRead()));
-
- // is the login process done already?
- if (ftp->state() == QFtp::LoggedIn)
- ftpDone();
-
- // no, defer the actual operation until after we've logged in
-}
-
-void QNetworkAccessFtpBackend::disconnectFromFtp(CacheCleanupMode mode)
-{
- state = Disconnecting;
-
- if (ftp) {
- disconnect(ftp, nullptr, this, nullptr);
-
- QByteArray key = makeCacheKey(url());
- if (mode == RemoveCachedConnection) {
- QNetworkAccessManagerPrivate::getObjectCache(this)->removeEntry(key);
- ftp->dispose();
- } else {
- QNetworkAccessManagerPrivate::getObjectCache(this)->releaseEntry(key);
- }
-
- ftp = nullptr;
- }
-}
-
-void QNetworkAccessFtpBackend::ftpDone()
-{
- // the last command we sent is done
- if (state == LoggingIn && ftp->state() != QFtp::LoggedIn) {
- if (ftp->state() == QFtp::Connected) {
- // the login did not succeed
- QUrl newUrl = url();
- QString userInfo = newUrl.userInfo();
- newUrl.setUserInfo(QString());
- setUrl(newUrl);
-
- QAuthenticator auth;
- authenticationRequired(&auth);
-
- if (!auth.isNull()) {
- // try again:
- newUrl.setUserName(auth.user());
- ftp->login(auth.user(), auth.password());
- return;
- }
-
- // Re insert the user info so that we can remove the cache entry.
- newUrl.setUserInfo(userInfo);
- setUrl(newUrl);
-
- error(QNetworkReply::AuthenticationRequiredError,
- tr("Logging in to %1 failed: authentication required")
- .arg(url().host()));
- } else {
- // we did not connect
- QNetworkReply::NetworkError code;
- switch (ftp->error()) {
- case QFtp::HostNotFound:
- code = QNetworkReply::HostNotFoundError;
- break;
-
- case QFtp::ConnectionRefused:
- code = QNetworkReply::ConnectionRefusedError;
- break;
-
- default:
- code = QNetworkReply::ProtocolFailure;
- break;
- }
-
- error(code, ftp->errorString());
- }
-
- // we're not connected, so remove the cache entry:
- disconnectFromFtp(RemoveCachedConnection);
- finished();
- return;
- }
-
- // check for errors:
- if (state == CheckingFeatures && ftp->error() == QFtp::UnknownError) {
- qWarning("QNetworkAccessFtpBackend: HELP command failed, ignoring it");
- ftp->clearError();
- } else if (ftp->error() != QFtp::NoError) {
- QString msg;
- if (operation() == QNetworkAccessManager::GetOperation)
- msg = tr("Error while downloading %1: %2");
- else
- msg = tr("Error while uploading %1: %2");
- msg = msg.arg(url().toString(), ftp->errorString());
-
- if (state == Statting)
- // file probably doesn't exist
- error(QNetworkReply::ContentNotFoundError, msg);
- else
- error(QNetworkReply::ContentAccessDenied, msg);
-
- disconnectFromFtp(RemoveCachedConnection);
- finished();
- }
-
- if (state == LoggingIn) {
- state = CheckingFeatures;
- // send help command to find out if server supports SIZE, MDTM, and PWD
- if (operation() == QNetworkAccessManager::GetOperation
- || operation() == QNetworkAccessManager::PutOperation) {
- helpId = ftp->rawCommand(QLatin1String("HELP")); // get supported commands
- } else {
- ftpDone();
- }
- } else if (state == CheckingFeatures) {
- // If a URL path starts with // prefix (/%2F decoded), the resource will
- // be retrieved by an absolute path starting with the root directory.
- // For the other URLs, the working directory is retrieved by PWD command
- // and prepended to the resource path as an absolute path starting with
- // the working directory.
- state = ResolvingPath;
- QString path = url().path();
- if (path.startsWith(QLatin1String("//")) || supportsPwd == false) {
- ftpDone(); // no commands sent, move to the next state
- } else {
- // If a path starts with /~/ prefix, its prefix will be replaced by
- // the working directory as an absolute path starting with working
- // directory.
- if (path.startsWith(QLatin1String("/~/"))) {
- // Remove leading /~ symbols
- QUrl newUrl = url();
- newUrl.setPath(path.mid(2));
- setUrl(newUrl);
- }
-
- // send PWD command to retrieve the working directory
- pwdId = ftp->rawCommand(QLatin1String("PWD"));
- }
- } else if (state == ResolvingPath) {
- state = Statting;
- if (operation() == QNetworkAccessManager::GetOperation) {
- // logged in successfully, send the stat requests (if supported)
- const QString path = url().path();
- if (supportsSize) {
- ftp->rawCommand(QLatin1String("TYPE I"));
- sizeId = ftp->rawCommand(QLatin1String("SIZE ") + path); // get size
- }
- if (supportsMdtm)
- mdtmId = ftp->rawCommand(QLatin1String("MDTM ") + path); // get modified time
- if (!supportsSize && !supportsMdtm)
- ftpDone(); // no commands sent, move to the next state
- } else {
- ftpDone();
- }
- } else if (state == Statting) {
- // statted successfully, send the actual request
- metaDataChanged();
- state = Transferring;
-
- QFtp::TransferType type = QFtp::Binary;
- if (operation() == QNetworkAccessManager::GetOperation) {
- setCachingEnabled(true);
- ftp->get(url().path(), nullptr, type);
- } else {
- ftp->put(uploadDevice, url().path(), type);
- }
-
- } else if (state == Transferring) {
- // upload or download finished
- disconnectFromFtp();
- finished();
- }
-}
-
-void QNetworkAccessFtpBackend::ftpReadyRead()
-{
- QByteArray data = ftp->readAll();
- QByteDataBuffer list;
- list.append(data);
- data.clear(); // important because of implicit sharing!
- writeDownstreamData(list);
-}
-
-void QNetworkAccessFtpBackend::ftpRawCommandReply(int code, const QString &text)
-{
- //qDebug() << "FTP reply:" << code << text;
- int id = ftp->currentId();
-
- if ((id == helpId) && ((code == 200) || (code == 214))) { // supported commands
- // the "FEAT" ftp command would be nice here, but it is not part of the
- // initial FTP RFC 959, neither ar "SIZE" nor "MDTM" (they are all specified
- // in RFC 3659)
- if (text.contains(QLatin1String("SIZE"), Qt::CaseSensitive))
- supportsSize = true;
- if (text.contains(QLatin1String("MDTM"), Qt::CaseSensitive))
- supportsMdtm = true;
- if (text.contains(QLatin1String("PWD"), Qt::CaseSensitive))
- supportsPwd = true;
- } else if (id == pwdId && code == 257) {
- QString pwdPath;
- int startIndex = text.indexOf('"');
- int stopIndex = text.lastIndexOf('"');
- if (stopIndex - startIndex) {
- // The working directory is a substring between \" symbols.
- startIndex++; // skip the first \" symbol
- pwdPath = text.mid(startIndex, stopIndex - startIndex);
- } else {
- // If there is no or only one \" symbol, use all the characters of
- // text.
- pwdPath = text;
- }
-
- // If a URL path starts with the working directory prefix, its resource
- // will be retrieved from the working directory. Otherwise, the path of
- // the working directory is prepended to the resource path.
- QString urlPath = url().path();
- if (!urlPath.startsWith(pwdPath)) {
- if (pwdPath.endsWith(QLatin1Char('/')))
- pwdPath.chop(1);
- // Prepend working directory to the URL path
- QUrl newUrl = url();
- newUrl.setPath(pwdPath % urlPath);
- setUrl(newUrl);
- }
- } else if (code == 213) { // file status
- if (id == sizeId) {
- // reply to the size command
- setHeader(QNetworkRequest::ContentLengthHeader, text.toLongLong());
-#if QT_CONFIG(datetimeparser)
- } else if (id == mdtmId) {
- QDateTime dt = QDateTime::fromString(text, QLatin1String("yyyyMMddHHmmss"));
- setHeader(QNetworkRequest::LastModifiedHeader, dt);
-#endif
- }
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkaccessftpbackend_p.h b/src/network/access/qnetworkaccessftpbackend_p.h
deleted file mode 100644
index 0b3d35dcd3..0000000000
--- a/src/network/access/qnetworkaccessftpbackend_p.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QNETWORKACCESSFTPBACKEND_P_H
-#define QNETWORKACCESSFTPBACKEND_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of the Network Access API. This header file may change from
-// version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include "qnetworkaccessbackend_p.h"
-#include "qnetworkaccesscache_p.h"
-#include "qnetworkrequest.h"
-#include "qnetworkreply.h"
-#include "private/qftp_p.h"
-
-#include "QtCore/qpointer.h"
-
-QT_REQUIRE_CONFIG(ftp);
-
-QT_BEGIN_NAMESPACE
-
-class QNetworkAccessFtpIODevice;
-class QNetworkAccessCachedFtpConnection;
-
-class QNetworkAccessFtpBackend: public QNetworkAccessBackend
-{
- Q_OBJECT
-public:
- enum State {
- Idle,
- //Connecting,
- LoggingIn,
- CheckingFeatures,
- ResolvingPath,
- Statting,
- Transferring,
- Disconnecting
- };
-
- QNetworkAccessFtpBackend();
- virtual ~QNetworkAccessFtpBackend();
-
- virtual void open() override;
- virtual void closeDownstreamChannel() override;
-
- virtual void downstreamReadyWrite() override;
-
- enum CacheCleanupMode {
- ReleaseCachedConnection,
- RemoveCachedConnection
- };
-
- void disconnectFromFtp(CacheCleanupMode mode = ReleaseCachedConnection);
-
-public slots:
- void ftpConnectionReady(QNetworkAccessCache::CacheableObject *object);
- void ftpDone();
- void ftpReadyRead();
- void ftpRawCommandReply(int code, const QString &text);
-
-private:
- friend class QNetworkAccessFtpIODevice;
- QPointer<QNetworkAccessCachedFtpConnection> ftp;
- QIODevice *uploadDevice;
- qint64 totalBytes;
- int helpId, sizeId, mdtmId, pwdId;
- bool supportsSize, supportsMdtm, supportsPwd;
- State state;
-};
-
-class QNetworkAccessFtpBackendFactory: public QNetworkAccessBackendFactory
-{
-public:
- virtual QStringList supportedSchemes() const override;
- virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op,
- const QNetworkRequest &request) const override;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index acec69f41f..b56da732e2 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -54,9 +54,6 @@
#include "qhstsstore_p.h"
#endif // QT_CONFIG(settings)
-#if QT_CONFIG(ftp)
-#include "qnetworkaccessftpbackend_p.h"
-#endif
#include "qnetworkaccessfilebackend_p.h"
#include "qnetworkaccessdebugpipebackend_p.h"
#include "qnetworkaccesscachebackend_p.h"
@@ -94,9 +91,6 @@
QT_BEGIN_NAMESPACE
Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
-#if QT_CONFIG(ftp)
-Q_GLOBAL_STATIC(QNetworkAccessFtpBackendFactory, ftpBackend)
-#endif // QT_CONFIG(ftp)
#ifdef QT_BUILD_INTERNAL
Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
@@ -159,10 +153,6 @@ bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString&
static void ensureInitialized()
{
-#if QT_CONFIG(ftp)
- (void) ftpBackend();
-#endif
-
#ifdef QT_BUILD_INTERNAL
(void) debugpipeBackend();
#endif
diff --git a/src/network/configure.cmake b/src/network/configure.cmake
index 71b2fdf884..e64a98415a 100644
--- a/src/network/configure.cmake
+++ b/src/network/configure.cmake
@@ -319,14 +319,6 @@ qt_feature_definition("sctp" "QT_NO_SCTP" NEGATE VALUE "1")
qt_feature("system-proxies" PRIVATE
LABEL "Use system proxies"
)
-qt_feature("ftp" PUBLIC
- SECTION "Networking"
- LABEL "FTP"
- PURPOSE "Provides support for the File Transfer Protocol in QNetworkAccessManager."
- AUTODETECT OFF
- CONDITION QT_FEATURE_textdate AND QT_FEATURE_regularexpression
-)
-qt_feature_definition("ftp" "QT_NO_FTP" NEGATE VALUE "1")
qt_feature("http" PUBLIC
SECTION "Networking"
LABEL "HTTP"
diff --git a/src/network/configure.json b/src/network/configure.json
index a8166340dc..ae3af28fec 100644
--- a/src/network/configure.json
+++ b/src/network/configure.json
@@ -354,14 +354,6 @@
"label": "Use system proxies",
"output": [ "privateFeature" ]
},
- "ftp": {
- "label": "FTP",
- "purpose": "Provides support for the File Transfer Protocol in QNetworkAccessManager.",
- "section": "Networking",
- "autoDetect": false,
- "condition": "features.textdate && features.regularexpression",
- "output": [ "publicFeature", "feature" ]
- },
"http": {
"label": "HTTP",
"purpose": "Provides support for the Hypertext Transfer Protocol in QNetworkAccessManager.",
@@ -498,7 +490,6 @@ For example:
"opensslv11",
"dtls",
"ocsp",
- "ftp",
"sctp",
"system-proxies",
"gssapi",
diff --git a/src/network/doc/snippets/code/src_network_access_qftp.cpp b/src/network/doc/snippets/code/src_network_access_qftp.cpp
deleted file mode 100644
index 8472477a01..0000000000
--- a/src/network/doc/snippets/code/src_network_access_qftp.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "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 Qt Company Ltd 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 THE COPYRIGHT
-** OWNER OR CONTRIBUTORS 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."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//! [0]
-QFtp *ftp = new QFtp(parent);
-ftp->connectToHost("ftp.qt-project.org");
-ftp->login();
-//! [0]
-
-
-//! [1]
-ftp->connectToHost("ftp.qt-project.org"); // id == 1
-ftp->login(); // id == 2
-ftp->cd("qt"); // id == 3
-ftp->get("INSTALL"); // id == 4
-ftp->close(); // id == 5
-//! [1]
-
-
-//! [2]
-start(1)
-stateChanged(HostLookup)
-stateChanged(Connecting)
-stateChanged(Connected)
-finished(1, false)
-
-start(2)
-stateChanged(LoggedIn)
-finished(2, false)
-
-start(3)
-finished(3, false)
-
-start(4)
-dataTransferProgress(0, 3798)
-dataTransferProgress(2896, 3798)
-readyRead()
-dataTransferProgress(3798, 3798)
-readyRead()
-finished(4, false)
-
-start(5)
-stateChanged(Closing)
-stateChanged(Unconnected)
-finished(5, false)
-
-done(false)
-//! [2]
-
-
-//! [3]
-start(1)
-stateChanged(HostLookup)
-stateChanged(Connecting)
-stateChanged(Connected)
-finished(1, false)
-
-start(2)
-finished(2, true)
-
-done(true)
-//! [3]
diff --git a/src/network/doc/src/examples.qdoc b/src/network/doc/src/examples.qdoc
index 3d31e04989..8dc598daff 100644
--- a/src/network/doc/src/examples.qdoc
+++ b/src/network/doc/src/examples.qdoc
@@ -51,7 +51,6 @@
\li \l{network/network-chat}{Network Chat}
\li \l{network/fortuneclient}{Fortune Client}\raisedaster
\li \l{network/fortuneserver}{Fortune Server}\raisedaster
- \li \l{network/qftp}{FTP}\raisedaster
\li \l{network/http}{HTTP}
\li \l{network/loopback}{Loopback}
\li \l{network/threadedfortuneserver}{Threaded Fortune Server}\raisedaster
diff --git a/src/network/doc/src/network-programming.qdoc b/src/network/doc/src/network-programming.qdoc
index 96bbd8d38b..4f2ebf7c54 100644
--- a/src/network/doc/src/network-programming.qdoc
+++ b/src/network/doc/src/network-programming.qdoc
@@ -51,7 +51,7 @@
The \l{Qt Network C++ Classes} page contains a list of the C++ classes
in Qt Network.
- \section1 High Level Network Operations for HTTP and FTP
+ \section1 High Level Network Operations for HTTP
The Network Access API is a collection of classes for performing
common network operations. The API provides an abstraction layer
@@ -64,7 +64,7 @@
with a request, such as any header information and the encryption
used. The URL specified when a request object is constructed
determines the protocol used for a request.
- Currently HTTP, FTP and local file URLs are supported for uploading
+ Currently HTTP and local file URLs are supported for uploading
and downloading.
The coordination of network operations is performed by the
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri
index c726515d15..cc78555805 100644
--- a/src/network/kernel/kernel.pri
+++ b/src/network/kernel/kernel.pri
@@ -33,11 +33,6 @@ qtConfig(topleveldomain) {
SOURCES += kernel/qtldurl.cpp
}
-qtConfig(ftp) {
- HEADERS += kernel/qurlinfo_p.h
- SOURCES += kernel/qurlinfo.cpp
-}
-
qtConfig(dnslookup) {
HEADERS += kernel/qdnslookup.h \
kernel/qdnslookup_p.h
diff --git a/src/network/kernel/qurlinfo.cpp b/src/network/kernel/qurlinfo.cpp
deleted file mode 100644
index e6f2e70ff4..0000000000
--- a/src/network/kernel/qurlinfo.cpp
+++ /dev/null
@@ -1,727 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qurlinfo_p.h"
-
-#include "qurl.h"
-#include "qdir.h"
-#include <limits.h>
-
-QT_BEGIN_NAMESPACE
-
-class QUrlInfoPrivate
-{
-public:
- QUrlInfoPrivate() :
- permissions(0),
- size(0),
- isDir(false),
- isFile(true),
- isSymLink(false),
- isWritable(true),
- isReadable(true),
- isExecutable(false)
- {}
-
- QString name;
- int permissions;
- QString owner;
- QString group;
- qint64 size;
-
- QDateTime lastModified;
- QDateTime lastRead;
- bool isDir;
- bool isFile;
- bool isSymLink;
- bool isWritable;
- bool isReadable;
- bool isExecutable;
-};
-
-
-/*!
- \class QUrlInfo
- \brief The QUrlInfo class stores information about URLs.
-
- \internal
- \ingroup io
- \ingroup network
- \inmodule QtNetwork
-
- The information about a URL that can be retrieved includes name(),
- permissions(), owner(), group(), size(), lastModified(),
- lastRead(), isDir(), isFile(), isSymLink(), isWritable(),
- isReadable() and isExecutable().
-
- You can create your own QUrlInfo objects passing in all the
- relevant information in the constructor, and you can modify a
- QUrlInfo; for each getter mentioned above there is an equivalent
- setter. Note that setting values does not affect the underlying
- resource that the QUrlInfo provides information about; for example
- if you call setWritable(true) on a read-only resource the only
- thing changed is the QUrlInfo object, not the resource.
-
- \sa QUrl, {FTP Example}
-*/
-
-/*!
- \enum QUrlInfo::PermissionSpec
-
- This enum is used by the permissions() function to report the
- permissions of a file.
-
- \value ReadOwner The file is readable by the owner of the file.
- \value WriteOwner The file is writable by the owner of the file.
- \value ExeOwner The file is executable by the owner of the file.
- \value ReadGroup The file is readable by the group.
- \value WriteGroup The file is writable by the group.
- \value ExeGroup The file is executable by the group.
- \value ReadOther The file is readable by anyone.
- \value WriteOther The file is writable by anyone.
- \value ExeOther The file is executable by anyone.
-*/
-
-/*!
- Constructs an invalid QUrlInfo object with default values.
-
- \sa isValid()
-*/
-
-QUrlInfo::QUrlInfo()
-{
- d = nullptr;
-}
-
-/*!
- Copy constructor, copies \a ui to this URL info object.
-*/
-
-QUrlInfo::QUrlInfo(const QUrlInfo &ui)
-{
- if (ui.d) {
- d = new QUrlInfoPrivate;
- *d = *ui.d;
- } else {
- d = nullptr;
- }
-}
-
-/*!
- Constructs a QUrlInfo object by specifying all the URL's
- information.
-
- The information that is passed is the \a name, file \a
- permissions, \a owner and \a group and the file's \a size. Also
- passed is the \a lastModified date/time and the \a lastRead
- date/time. Flags are also passed, specifically, \a isDir, \a
- isFile, \a isSymLink, \a isWritable, \a isReadable and \a
- isExecutable.
-*/
-
-QUrlInfo::QUrlInfo(const QString &name, int permissions, const QString &owner,
- const QString &group, qint64 size, const QDateTime &lastModified,
- const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink,
- bool isWritable, bool isReadable, bool isExecutable)
-{
- d = new QUrlInfoPrivate;
- d->name = name;
- d->permissions = permissions;
- d->owner = owner;
- d->group = group;
- d->size = size;
- d->lastModified = lastModified;
- d->lastRead = lastRead;
- d->isDir = isDir;
- d->isFile = isFile;
- d->isSymLink = isSymLink;
- d->isWritable = isWritable;
- d->isReadable = isReadable;
- d->isExecutable = isExecutable;
-}
-
-
-/*!
- Constructs a QUrlInfo object by specifying all the URL's
- information.
-
- The information that is passed is the \a url, file \a
- permissions, \a owner and \a group and the file's \a size. Also
- passed is the \a lastModified date/time and the \a lastRead
- date/time. Flags are also passed, specifically, \a isDir, \a
- isFile, \a isSymLink, \a isWritable, \a isReadable and \a
- isExecutable.
-*/
-
-QUrlInfo::QUrlInfo(const QUrl &url, int permissions, const QString &owner,
- const QString &group, qint64 size, const QDateTime &lastModified,
- const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink,
- bool isWritable, bool isReadable, bool isExecutable)
-{
- d = new QUrlInfoPrivate;
- d->name = QFileInfo(url.path()).fileName();
- d->permissions = permissions;
- d->owner = owner;
- d->group = group;
- d->size = size;
- d->lastModified = lastModified;
- d->lastRead = lastRead;
- d->isDir = isDir;
- d->isFile = isFile;
- d->isSymLink = isSymLink;
- d->isWritable = isWritable;
- d->isReadable = isReadable;
- d->isExecutable = isExecutable;
-}
-
-
-/*!
- Sets the name of the URL to \a name. The name is the full text,
- for example, "http://qt-project.org/doc/qt-5.0/qtcore/qurl.html".
-
- If you call this function for an invalid URL info, this function
- turns it into a valid one.
-
- \sa isValid()
-*/
-
-void QUrlInfo::setName(const QString &name)
-{
- if (!d)
- d = new QUrlInfoPrivate;
- d->name = name;
-}
-
-
-/*!
- If \a b is true then the URL is set to be a directory; if \a b is
- false then the URL is set not to be a directory (which normally
- means it is a file). (Note that a URL can refer to both a file and
- a directory even though most file systems do not support this.)
-
- If you call this function for an invalid URL info, this function
- turns it into a valid one.
-
- \sa isValid()
-*/
-
-void QUrlInfo::setDir(bool b)
-{
- if (!d)
- d = new QUrlInfoPrivate;
- d->isDir = b;
-}
-
-
-/*!
- If \a b is true then the URL is set to be a file; if \b is false
- then the URL is set not to be a file (which normally means it is a
- directory). (Note that a URL can refer to both a file and a
- directory even though most file systems do not support this.)
-
- If you call this function for an invalid URL info, this function
- turns it into a valid one.
-
- \sa isValid()
-*/
-
-void QUrlInfo::setFile(bool b)
-{
- if (!d)
- d = new QUrlInfoPrivate;
- d->isFile = b;
-}
-
-
-/*!
- Specifies that the URL refers to a symbolic link if \a b is true
- and that it does not if \a b is false.
-
- If you call this function for an invalid URL info, this function
- turns it into a valid one.
-
- \sa isValid()
-*/
-
-void QUrlInfo::setSymLink(bool b)
-{
- if (!d)
- d = new QUrlInfoPrivate;
- d->isSymLink = b;
-}
-
-
-/*!
- Specifies that the URL is writable if \a b is true and not
- writable if \a b is false.
-
- If you call this function for an invalid URL info, this function
- turns it into a valid one.
-
- \sa isValid()
-*/
-
-void QUrlInfo::setWritable(bool b)
-{
- if (!d)
- d = new QUrlInfoPrivate;
- d->isWritable = b;
-}
-
-
-/*!
- Specifies that the URL is readable if \a b is true and not
- readable if \a b is false.
-
- If you call this function for an invalid URL info, this function
- turns it into a valid one.
-
- \sa isValid()
-*/
-
-void QUrlInfo::setReadable(bool b)
-{
- if (!d)
- d = new QUrlInfoPrivate;
- d->isReadable = b;
-}
-
-/*!
- Specifies that the owner of the URL is called \a s.
-
- If you call this function for an invalid URL info, this function
- turns it into a valid one.
-
- \sa isValid()
-*/
-
-void QUrlInfo::setOwner(const QString &s)
-{
- if (!d)
- d = new QUrlInfoPrivate;
- d->owner = s;
-}
-
-/*!
- Specifies that the owning group of the URL is called \a s.
-
- If you call this function for an invalid URL info, this function
- turns it into a valid one.
-
- \sa isValid()
-*/
-
-void QUrlInfo::setGroup(const QString &s)
-{
- if (!d)
- d = new QUrlInfoPrivate;
- d->group = s;
-}
-
-/*!
- Specifies the \a size of the URL.
-
- If you call this function for an invalid URL info, this function
- turns it into a valid one.
-
- \sa isValid()
-*/
-
-void QUrlInfo::setSize(qint64 size)
-{
- if (!d)
- d = new QUrlInfoPrivate;
- d->size = size;
-}
-
-/*!
- Specifies that the URL has access permissions \a p.
-
- If you call this function for an invalid URL info, this function
- turns it into a valid one.
-
- \sa isValid()
-*/
-
-void QUrlInfo::setPermissions(int p)
-{
- if (!d)
- d = new QUrlInfoPrivate;
- d->permissions = p;
-}
-
-/*!
- Specifies that the object the URL refers to was last modified at
- \a dt.
-
- If you call this function for an invalid URL info, this function
- turns it into a valid one.
-
- \sa isValid()
-*/
-
-void QUrlInfo::setLastModified(const QDateTime &dt)
-{
- if (!d)
- d = new QUrlInfoPrivate;
- d->lastModified = dt;
-}
-
-/*!
- \since 4.4
-
- Specifies that the object the URL refers to was last read at
- \a dt.
-
- If you call this function for an invalid URL info, this function
- turns it into a valid one.
-
- \sa isValid()
-*/
-
-void QUrlInfo::setLastRead(const QDateTime &dt)
-{
- if (!d)
- d = new QUrlInfoPrivate;
- d->lastRead = dt;
-}
-
-/*!
- Destroys the URL info object.
-*/
-
-QUrlInfo::~QUrlInfo()
-{
- delete d;
-}
-
-/*!
- Assigns the values of \a ui to this QUrlInfo object.
-*/
-
-QUrlInfo &QUrlInfo::operator=(const QUrlInfo &ui)
-{
- if (ui.d) {
- if (!d)
- d= new QUrlInfoPrivate;
- *d = *ui.d;
- } else {
- delete d;
- d = nullptr;
- }
- return *this;
-}
-
-/*!
- Returns the file name of the URL.
-
- \sa isValid()
-*/
-
-QString QUrlInfo::name() const
-{
- if (!d)
- return QString();
- return d->name;
-}
-
-/*!
- Returns the permissions of the URL. You can use the \c PermissionSpec flags
- to test for certain permissions.
-
- \sa isValid()
-*/
-
-int QUrlInfo::permissions() const
-{
- if (!d)
- return 0;
- return d->permissions;
-}
-
-/*!
- Returns the owner of the URL.
-
- \sa isValid()
-*/
-
-QString QUrlInfo::owner() const
-{
- if (!d)
- return QString();
- return d->owner;
-}
-
-/*!
- Returns the group of the URL.
-
- \sa isValid()
-*/
-
-QString QUrlInfo::group() const
-{
- if (!d)
- return QString();
- return d->group;
-}
-
-/*!
- Returns the size of the URL.
-
- \sa isValid()
-*/
-
-qint64 QUrlInfo::size() const
-{
- if (!d)
- return 0;
- return d->size;
-}
-
-/*!
- Returns the last modification date of the URL.
-
- \sa isValid()
-*/
-
-QDateTime QUrlInfo::lastModified() const
-{
- if (!d)
- return QDateTime();
- return d->lastModified;
-}
-
-/*!
- Returns the date when the URL was last read.
-
- \sa isValid()
-*/
-
-QDateTime QUrlInfo::lastRead() const
-{
- if (!d)
- return QDateTime();
- return d->lastRead;
-}
-
-/*!
- Returns \c true if the URL is a directory; otherwise returns \c false.
-
- \sa isValid()
-*/
-
-bool QUrlInfo::isDir() const
-{
- if (!d)
- return false;
- return d->isDir;
-}
-
-/*!
- Returns \c true if the URL is a file; otherwise returns \c false.
-
- \sa isValid()
-*/
-
-bool QUrlInfo::isFile() const
-{
- if (!d)
- return false;
- return d->isFile;
-}
-
-/*!
- Returns \c true if the URL is a symbolic link; otherwise returns \c false.
-
- \sa isValid()
-*/
-
-bool QUrlInfo::isSymLink() const
-{
- if (!d)
- return false;
- return d->isSymLink;
-}
-
-/*!
- Returns \c true if the URL is writable; otherwise returns \c false.
-
- \sa isValid()
-*/
-
-bool QUrlInfo::isWritable() const
-{
- if (!d)
- return false;
- return d->isWritable;
-}
-
-/*!
- Returns \c true if the URL is readable; otherwise returns \c false.
-
- \sa isValid()
-*/
-
-bool QUrlInfo::isReadable() const
-{
- if (!d)
- return false;
- return d->isReadable;
-}
-
-/*!
- Returns \c true if the URL is executable; otherwise returns \c false.
-
- \sa isValid()
-*/
-
-bool QUrlInfo::isExecutable() const
-{
- if (!d)
- return false;
- return d->isExecutable;
-}
-
-/*!
- Returns \c true if \a i1 is greater than \a i2; otherwise returns
- false. The objects are compared by the value, which is specified
- by \a sortBy. This must be one of QDir::Name, QDir::Time or
- QDir::Size.
-*/
-
-bool QUrlInfo::greaterThan(const QUrlInfo &i1, const QUrlInfo &i2,
- int sortBy)
-{
- switch (sortBy) {
- case QDir::Name:
- return i1.name() > i2.name();
- case QDir::Time:
- return i1.lastModified() > i2.lastModified();
- case QDir::Size:
- return i1.size() > i2.size();
- default:
- return false;
- }
-}
-
-/*!
- Returns \c true if \a i1 is less than \a i2; otherwise returns \c false.
- The objects are compared by the value, which is specified by \a
- sortBy. This must be one of QDir::Name, QDir::Time or QDir::Size.
-*/
-
-bool QUrlInfo::lessThan(const QUrlInfo &i1, const QUrlInfo &i2,
- int sortBy)
-{
- return !greaterThan(i1, i2, sortBy);
-}
-
-/*!
- Returns \c true if \a i1 equals to \a i2; otherwise returns \c false.
- The objects are compared by the value, which is specified by \a
- sortBy. This must be one of QDir::Name, QDir::Time or QDir::Size.
-*/
-
-bool QUrlInfo::equal(const QUrlInfo &i1, const QUrlInfo &i2,
- int sortBy)
-{
- switch (sortBy) {
- case QDir::Name:
- return i1.name() == i2.name();
- case QDir::Time:
- return i1.lastModified() == i2.lastModified();
- case QDir::Size:
- return i1.size() == i2.size();
- default:
- return false;
- }
-}
-
-/*!
- Returns \c true if this QUrlInfo is equal to \a other; otherwise
- returns \c false.
-
- \sa lessThan(), equal()
-*/
-
-bool QUrlInfo::operator==(const QUrlInfo &other) const
-{
- if (!d)
- return other.d == nullptr;
- if (!other.d)
- return false;
-
- return (d->name == other.d->name &&
- d->permissions == other.d->permissions &&
- d->owner == other.d->owner &&
- d->group == other.d->group &&
- d->size == other.d->size &&
- d->lastModified == other.d->lastModified &&
- d->lastRead == other.d->lastRead &&
- d->isDir == other.d->isDir &&
- d->isFile == other.d->isFile &&
- d->isSymLink == other.d->isSymLink &&
- d->isWritable == other.d->isWritable &&
- d->isReadable == other.d->isReadable &&
- d->isExecutable == other.d->isExecutable);
-}
-
-/*!
- \fn bool QUrlInfo::operator!=(const QUrlInfo &other) const
- \since 4.2
-
- Returns \c true if this QUrlInfo is not equal to \a other; otherwise
- returns \c false.
-
- \sa lessThan(), equal()
-*/
-
-/*!
- Returns \c true if the URL info is valid; otherwise returns \c false.
- Valid means that the QUrlInfo contains real information.
-
- You should always check if the URL info is valid before relying on
- the values.
-*/
-bool QUrlInfo::isValid() const
-{
- return d != nullptr;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/kernel/qurlinfo_p.h b/src/network/kernel/qurlinfo_p.h
deleted file mode 100644
index 8180796f49..0000000000
--- a/src/network/kernel/qurlinfo_p.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QURLINFO_H
-#define QURLINFO_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtNetwork/private/qtnetworkglobal_p.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qiodevice.h>
-
-QT_REQUIRE_CONFIG(ftp);
-
-QT_BEGIN_NAMESPACE
-
-class QUrl;
-class QUrlInfoPrivate;
-
-class Q_NETWORK_EXPORT QUrlInfo
-{
-public:
- enum PermissionSpec {
- ReadOwner = 00400, WriteOwner = 00200, ExeOwner = 00100,
- ReadGroup = 00040, WriteGroup = 00020, ExeGroup = 00010,
- ReadOther = 00004, WriteOther = 00002, ExeOther = 00001 };
-
- QUrlInfo();
- QUrlInfo(const QUrlInfo &ui);
- QUrlInfo(const QString &name, int permissions, const QString &owner,
- const QString &group, qint64 size, const QDateTime &lastModified,
- const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink,
- bool isWritable, bool isReadable, bool isExecutable);
- QUrlInfo(const QUrl &url, int permissions, const QString &owner,
- const QString &group, qint64 size, const QDateTime &lastModified,
- const QDateTime &lastRead, bool isDir, bool isFile, bool isSymLink,
- bool isWritable, bool isReadable, bool isExecutable);
- QUrlInfo &operator=(const QUrlInfo &ui);
- virtual ~QUrlInfo();
-
- virtual void setName(const QString &name);
- virtual void setDir(bool b);
- virtual void setFile(bool b);
- virtual void setSymLink(bool b);
- virtual void setOwner(const QString &s);
- virtual void setGroup(const QString &s);
- virtual void setSize(qint64 size);
- virtual void setWritable(bool b);
- virtual void setReadable(bool b);
- virtual void setPermissions(int p);
- virtual void setLastModified(const QDateTime &dt);
- void setLastRead(const QDateTime &dt);
-
- bool isValid() const;
-
- QString name() const;
- int permissions() const;
- QString owner() const;
- QString group() const;
- qint64 size() const;
- QDateTime lastModified() const;
- QDateTime lastRead() const;
- bool isDir() const;
- bool isFile() const;
- bool isSymLink() const;
- bool isWritable() const;
- bool isReadable() const;
- bool isExecutable() const;
-
- static bool greaterThan(const QUrlInfo &i1, const QUrlInfo &i2,
- int sortBy);
- static bool lessThan(const QUrlInfo &i1, const QUrlInfo &i2,
- int sortBy);
- static bool equal(const QUrlInfo &i1, const QUrlInfo &i2,
- int sortBy);
-
- bool operator==(const QUrlInfo &i) const;
- inline bool operator!=(const QUrlInfo &i) const
- { return !operator==(i); }
-
-private:
- QUrlInfoPrivate *d;
-};
-
-QT_END_NAMESPACE
-
-#endif // QURLINFO_H
diff --git a/tests/auto/network/access/CMakeLists.txt b/tests/auto/network/access/CMakeLists.txt
index 1fa4ab6c6e..d225eb1299 100644
--- a/tests/auto/network/access/CMakeLists.txt
+++ b/tests/auto/network/access/CMakeLists.txt
@@ -16,6 +16,3 @@ if(QT_FEATURE_private_tests)
add_subdirectory(hsts)
add_subdirectory(qdecompresshelper)
endif()
-if(QT_FEATURE_ftp AND QT_FEATURE_private_tests)
- add_subdirectory(qftp)
-endif()
diff --git a/tests/auto/network/access/access.pro b/tests/auto/network/access/access.pro
index 1cd488baf9..45d7b0cda5 100644
--- a/tests/auto/network/access/access.pro
+++ b/tests/auto/network/access/access.pro
@@ -24,5 +24,3 @@ SUBDIRS=\
http2 \
hsts \
qdecompresshelper
-
-qtConfig(ftp): qtConfig(private_tests): SUBDIRS += qftp
diff --git a/tests/auto/network/access/qftp/.gitattributes b/tests/auto/network/access/qftp/.gitattributes
deleted file mode 100644
index e04709aa2e..0000000000
--- a/tests/auto/network/access/qftp/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-rfc3252.txt -crlf
diff --git a/tests/auto/network/access/qftp/.gitignore b/tests/auto/network/access/qftp/.gitignore
deleted file mode 100644
index 7a4845df05..0000000000
--- a/tests/auto/network/access/qftp/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-tst_qftp
-tst_QFtp_activeMode_inittab
diff --git a/tests/auto/network/access/qftp/BLACKLIST b/tests/auto/network/access/qftp/BLACKLIST
deleted file mode 100644
index 0a99f3eb00..0000000000
--- a/tests/auto/network/access/qftp/BLACKLIST
+++ /dev/null
@@ -1,16 +0,0 @@
-# QTBUG-15111
-
-[activeMode:WithoutProxy]
-redhatenterpriselinuxworkstation-6.6
-
-[activeMode:WithoutProxyWithSession]
-redhatenterpriselinuxworkstation-6.6
-
-[list]
-opensuse-leap
-windows-7sp1
-windows-10 msvc-2015
-ubuntu
-osx
-[list:epsvNotSupported]
-*
diff --git a/tests/auto/network/access/qftp/CMakeLists.txt b/tests/auto/network/access/qftp/CMakeLists.txt
deleted file mode 100644
index f67ddd3326..0000000000
--- a/tests/auto/network/access/qftp/CMakeLists.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-# Generated from qftp.pro.
-
-if(NOT QT_FEATURE_ftp)
- return()
-endif()
-if(NOT QT_FEATURE_private_tests)
- return()
-endif()
-
-#####################################################################
-## tst_qftp Test:
-#####################################################################
-
-qt_add_test(tst_qftp
- SOURCES
- tst_qftp.cpp
- PUBLIC_LIBRARIES
- Qt::Network
- Qt::NetworkPrivate
-)
-
-#### Keys ignored in scope 1:.:.:qftp.pro:<TRUE>:
-# QT_FOR_CONFIG = "network"
-# QT_TEST_SERVER_LIST = "vsftpd" "ftp-proxy" "squid" "danted"
-# _REQUIREMENTS = "qtConfig(ftp)" "qtConfig(private_tests)"
diff --git a/tests/auto/network/access/qftp/qftp.pro b/tests/auto/network/access/qftp/qftp.pro
deleted file mode 100644
index ad610316df..0000000000
--- a/tests/auto/network/access/qftp/qftp.pro
+++ /dev/null
@@ -1,11 +0,0 @@
-CONFIG += testcase
-TARGET = tst_qftp
-SOURCES += tst_qftp.cpp
-QT_FOR_CONFIG += network
-
-requires(qtConfig(ftp))
-requires(qtConfig(private_tests))
-QT = core network network-private testlib
-
-CONFIG += unsupported/testserver
-QT_TEST_SERVER_LIST = vsftpd ftp-proxy squid danted
diff --git a/tests/auto/network/access/qftp/rfc3252.txt b/tests/auto/network/access/qftp/rfc3252.txt
deleted file mode 100644
index b80c61bf0a..0000000000
--- a/tests/auto/network/access/qftp/rfc3252.txt
+++ /dev/null
@@ -1,899 +0,0 @@
-
-
-
-
-
-
-Network Working Group H. Kennedy
-Request for Comments: 3252 Mimezine
-Category: Informational 1 April 2002
-
-
- Binary Lexical Octet Ad-hoc Transport
-
-Status of this Memo
-
- This memo provides information for the Internet community. It does
- not specify an Internet standard of any kind. Distribution of this
- memo is unlimited.
-
-Copyright Notice
-
- Copyright (C) The Internet Society (2002). All Rights Reserved.
-
-Abstract
-
- This document defines a reformulation of IP and two transport layer
- protocols (TCP and UDP) as XML applications.
-
-1. Introduction
-
-1.1. Overview
-
- This document describes the Binary Lexical Octet Ad-hoc Transport
- (BLOAT): a reformulation of a widely-deployed network-layer protocol
- (IP [RFC791]), and two associated transport layer protocols (TCP
- [RFC793] and UDP [RFC768]) as XML [XML] applications. It also
- describes methods for transporting BLOAT over Ethernet and IEEE 802
- networks as well as encapsulating BLOAT in IP for gatewaying BLOAT
- across the public Internet.
-
-1.2. Motivation
-
- The wild popularity of XML as a basis for application-level protocols
- such as the Blocks Extensible Exchange Protocol [RFC3080], the Simple
- Object Access Protocol [SOAP], and Jabber [JABBER] prompted
- investigation into the possibility of extending the use of XML in the
- protocol stack. Using XML at both the transport and network layer in
- addition to the application layer would provide for an amazing amount
- of power and flexibility while removing dependencies on proprietary
- and hard-to-understand binary protocols. This protocol unification
- would also allow applications to use a single XML parser for all
- aspects of their operation, eliminating developer time spent figuring
- out the intricacies of each new protocol, and moving the hard work of
-
-
-
-
-Kennedy Informational [Page 1]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
- parsing to the XML toolset. The use of XML also mitigates concerns
- over "network vs. host" byte ordering which is at the root of many
- network application bugs.
-
-1.3. Relation to Existing Protocols
-
- The reformulations specified in this RFC follow as closely as
- possible the spirit of the RFCs on which they are based, and so MAY
- contain elements or attributes that would not be needed in a pure
- reworking (e.g. length attributes, which are implicit in XML.)
-
- The layering of network and transport protocols are maintained in
- this RFC despite the optimizations that could be made if the line
- were somewhat blurred (i.e. merging TCP and IP into a single, larger
- element in the DTD) in order to foster future use of this protocol as
- a basis for reformulating other protocols (such as ICMP.)
-
- Other than the encoding, the behavioral aspects of each of the
- existing protocols remain unchanged. Routing, address spaces, TCP
- congestion control, etc. behave as specified in the extant standards.
- Adapting to new standards and experimental algorithm heuristics for
- improving performance will become much easier once the move to BLOAT
- has been completed.
-
-1.4. Requirement Levels
-
- The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
- "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
- document are to be interpreted as described in BCP 14, RFC 2119
- [RFC2119].
-
-2. IPoXML
-
- This protocol MUST be implemented to be compliant with this RFC.
- IPoXML is the root protocol REQUIRED for effective use of TCPoXML
- (section 3.) and higher-level application protocols.
-
- The DTD for this document type can be found in section 7.1.
-
- The routing of IPoXML can be easily implemented on hosts with an XML
- parser, as the regular structure lends itself handily to parsing and
- validation of the document/datagram and then processing the
- destination address, TTL, and checksum before sending it on to its
- next-hop.
-
- The reformulation of IPv4 was chosen over IPv6 [RFC2460] due to the
- wider deployment of IPv4 and the fact that implementing IPv6 as XML
- would have exceeded the 1500 byte Ethernet MTU.
-
-
-
-Kennedy Informational [Page 2]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
- All BLOAT implementations MUST use - and specify - the UTF-8 encoding
- of RFC 2279 [RFC2279]. All BLOAT document/datagrams MUST be well-
- formed and include the XMLDecl.
-
-2.1. IP Description
-
- A number of items have changed (for the better) from the original IP
- specification. Bit-masks, where present have been converted into
- human-readable values. IP addresses are listed in their dotted-
- decimal notation [RFC1123]. Length and checksum values are present
- as decimal integers.
-
- To calculate the length and checksum fields of the IP element, a
- canonicalized form of the element MUST be used. The canonical form
- SHALL have no whitespace (including newline characters) between
- elements and only one space character between attributes. There
- SHALL NOT be a space following the last attribute in an element.
-
- An iterative method SHOULD be used to calculate checksums, as the
- length field will vary based on the size of the checksum.
-
- The payload element bears special attention. Due to the character
- set restrictions of XML, the payload of IP datagrams (which MAY
- contain arbitrary data) MUST be encoded for transport. This RFC
- REQUIRES the contents of the payload to be encoded in the base-64
- encoding of RFC 2045 [RFC2045], but removes the requirement that the
- encoded output MUST be wrapped on 76-character lines.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Kennedy Informational [Page 3]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
-2.2. Example Datagram
-
- The following is an example IPoXML datagram with an empty payload:
-
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd">
- <ip>
- <header length="474">
- <version value="4"/>
- <tos precedence="Routine" delay="Normal" throughput="Normal"
- relibility="Normal" reserved="0"/>
- <total.length value="461"/>
- <id value="1"/>
- <flags reserved="0" df="dont" mf="last"/>
- <offset value="0"/>
- <ttl value="255"/>
- <protocol value="6"/>
- <checksum value="8707"/>
- <source address="10.0.0.22"/>
- <destination address="10.0.0.1"/>
- <options>
- <end copied="0" class="0" number="0"/>
- </options>
- <padding pad="0"/>
- </header>
- <payload>
- </payload>
- </ip>
-
-3. TCPoXML
-
- This protocol MUST be implemented to be compliant with this RFC. The
- DTD for this document type can be found in section 7.2.
-
-3.1. TCP Description
-
- A number of items have changed from the original TCP specification.
- Bit-masks, where present have been converted into human-readable
- values. Length and checksum and port values are present as decimal
- integers.
-
- To calculate the length and checksum fields of the TCP element, a
- canonicalized form of the element MUST be used as in section 2.1.
-
- An iterative method SHOULD be used to calculate checksums as in
- section 2.1.
-
- The payload element MUST be encoded as in section 2.1.
-
-
-
-Kennedy Informational [Page 4]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
- The TCP offset element was expanded to a maximum of 255 from 16 to
- allow for the increased size of the header in XML.
-
- TCPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header
- as well as the <!DOCTYPE> declaration.
-
-3.2. Example Datagram
-
- The following is an example TCPoXML datagram with an empty payload:
-
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd">
- <tcp>
- <tcp.header>
- <src port="31415"/>
- <dest port="42424"/>
- <sequence number="322622954"/>
- <acknowledgement number="689715995"/>
- <offset number=""/>
- <reserved value="0"/>
- <control syn="1" ack="1"/>
- <window size="1"/>
- <urgent pointer="0"/>
- <checksum value="2988"/>
- <tcp.options>
- <tcp.end kind="0"/>
- </tcp.options>
- <padding pad="0"/>
- </tcp.header>
- <payload>
- </payload>
- </tcp>
-
-4. UDPoXML
-
- This protocol MUST be implemented to be compliant with this RFC. The
- DTD for this document type can be found in section 7.3.
-
-4.1. UDP Description
-
- A number of items have changed from the original UDP specification.
- Bit-masks, where present have been converted into human-readable
- values. Length and checksum and port values are present as decimal
- integers.
-
-
-
-
-
-
-
-Kennedy Informational [Page 5]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
- To calculate the length and checksum fields of the UDP element, a
- canonicalized form of the element MUST be used as in section 2.1. An
- iterative method SHOULD be used to calculate checksums as in section
- 2.1.
-
- The payload element MUST be encoded as in section 2.1.
-
- UDPoXML datagrams encapsulated by IPoXML MAY omit the <?xml?> header
- as well as the <!DOCTYPE> declaration.
-
-4.2. Example Datagram
-
- The following is an example UDPoXML datagram with an empty payload:
-
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd">
- <udp>
- <udp.header>
- <src port="31415"/>
- <dest port="42424"/>
- <udp.length value="143"/>
- <checksum value="2988"/>
- </udp.header>
- <payload>
- </payload>
- </udp>
-
-5. Network Transport
-
- This document provides for the transmission of BLOAT datagrams over
- two common families of physical layer transport. Future RFCs will
- address additional transports as routing vendors catch up to the
- specification, and we begin to see BLOAT routed across the Internet
- backbone.
-
-5.1. Ethernet
-
- BLOAT is encapsulated in Ethernet datagrams as in [RFC894] with the
- exception that the type field of the Ethernet frame MUST contain the
- value 0xBEEF. The first 5 octets of the Ethernet frame payload will
- be 0x3c 3f 78 6d 6c ("<?xml".)
-
-5.2. IEEE 802
-
- BLOAT is encapsulated in IEEE 802 Networks as in [RFC1042] except
- that the protocol type code for IPoXML is 0xBEEF.
-
-
-
-
-
-Kennedy Informational [Page 6]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
-6. Gatewaying over IP
-
- In order to facilitate the gradual introduction of BLOAT into the
- public Internet, BLOAT MAY be encapsulated in IP as in [RFC2003] to
- gateway between networks that run BLOAT natively on their LANs.
-
-7. DTDs
-
- The Transport DTDs (7.2. and 7.3.) build on the definitions in the
- Network DTD (7.1.)
-
- The DTDs are referenced by their PubidLiteral and SystemLiteral (from
- [XML]) although it is understood that most IPoXML implementations
- will not need to pull down the DTD, as it will normally be embedded
- in the implementation, and presents something of a catch-22 if you
- need to load part of your network protocol over the network.
-
-7.1. IPoXML DTD
-
- <!--
- DTD for IP over XML.
- Refer to this DTD as:
-
- <!DOCTYPE ip PUBLIC "-//IETF//DTD BLOAT 1.0 IP//EN" "bloat.dtd">
- -->
- <!--
- DTD data types:
-
- Digits [0..9]+
-
- Precedence "NetworkControl | InternetworkControl |
- CRITIC | FlashOverride | Flash | Immediate |
- Priority | Routine"
-
- IP4Addr "dotted-decimal" notation of [RFC1123]
-
- Class [0..3]
-
- Sec "Unclassified | Confidential | EFTO | MMMM | PROG |
- Restricted | Secret | Top Secret | Reserved"
-
- Compartments [0..65535]
-
- Handling [0..65535]
-
- TCC [0..16777216]
-
- -->
-
-
-
-Kennedy Informational [Page 7]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
- <!ENTITY % Digits "CDATA">
- <!ENTITY % Precedence "CDATA">
- <!ENTITY % IP4Addr "CDATA">
- <!ENTITY % Class "CDATA">
- <!ENTITY % Sec "CDATA">
- <!ENTITY % Compartments "CDATA">
- <!ENTITY % Handling "CDATA">
- <!ENTITY % TCC "CDATA">
-
- <!ELEMENT ip (header, payload)>
-
- <!ELEMENT header (version, tos, total.length, id, flags, offset, ttl,
- protocol, checksum, source, destination, options,
- padding)>
- <!-- length of header in 32-bit words -->
- <!ATTLIST header
- length %Digits; #REQUIRED>
-
- <!ELEMENT version EMPTY>
- <!-- ip version. SHOULD be "4" -->
- <!ATTLIST version
- value %Digits; #REQUIRED>
-
- <!ELEMENT tos EMPTY>
- <!ATTLIST tos
- precedence %Precedence; #REQUIRED
- delay (normal | low) #REQUIRED
- throughput (normal | high) #REQUIRED
- relibility (normal | high) #REQUIRED
- reserved CDATA #FIXED "0">
-
- <!ELEMENT total.length EMPTY>
- <!--
- total length of datagram (header and payload) in octets, MUST be
- less than 65,535 (and SHOULD be less than 1024 for IPoXML on local
- ethernets).
- -->
- <!ATTLIST total.length
- value %Digits; #REQUIRED>
-
- <!ELEMENT id EMPTY>
- <!-- 0 <= id <= 65,535 -->
- <!ATTLIST id
- value %Digits; #REQUIRED>
-
- <!ELEMENT flags EMPTY>
- <!-- df = don't fragment, mf = more fragments -->
- <!ATTLIST flags
-
-
-
-Kennedy Informational [Page 8]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
- reserved CDATA #FIXED "0"
- df (may|dont) #REQUIRED
- mf (last|more) #REQUIRED>
-
- <!ELEMENT offset EMPTY>
- <!-- 0 <= offset <= 8192 measured in 8 octet (64-bit) chunks -->
- <!ATTLIST offset
- value %Digits; #REQUIRED>
-
- <!ELEMENT ttl EMPTY>
- <!-- 0 <= ttl <= 255 -->
- <!ATTLIST ttl
- value %Digits; #REQUIRED>
-
- <!ELEMENT protocol EMPTY>
- <!-- 0 <= protocol <= 255 (per IANA) -->
- <!ATTLIST protocol
- value %Digits; #REQUIRED>
-
- <!ELEMENT checksum EMPTY>
- <!-- 0 <= checksum <= 65535 (over header only) -->
- <!ATTLIST checksum
- value %Digits; #REQUIRED>
-
- <!ELEMENT source EMPTY>
- <!ATTLIST source
- address %IP4Addr; #REQUIRED>
-
- <!ELEMENT destination EMPTY>
- <!ATTLIST destination
- address %IP4Addr; #REQUIRED>
-
- <!ELEMENT options ( end | noop | security | loose | strict | record
- | stream | timestamp )*>
-
- <!ELEMENT end EMPTY>
- <!ATTLIST end
- copied (0|1) #REQUIRED
- class CDATA #FIXED "0"
- number CDATA #FIXED "0">
-
- <!ELEMENT noop EMPTY>
- <!ATTLIST noop
- copied (0|1) #REQUIRED
- class CDATA #FIXED "0"
- number CDATA #FIXED "1">
-
- <!ELEMENT security EMPTY>
-
-
-
-Kennedy Informational [Page 9]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
- <!ATTLIST security
- copied CDATA #FIXED "1"
- class CDATA #FIXED "0"
- number CDATA #FIXED "2"
- length CDATA #FIXED "11"
- security %Sec; #REQUIRED
- compartments %Compartments; #REQUIRED
- handling %Handling; #REQUIRED
- tcc %TCC; #REQUIRED>
- <!ELEMENT loose (hop)+>
- <!ATTLIST loose
- copied CDATA #FIXED "1"
- class CDATA #FIXED "0"
- number CDATA #FIXED "3"
- length %Digits; #REQUIRED
- pointer %Digits; #REQUIRED>
-
- <!ELEMENT hop EMPTY>
- <!ATTLIST hop
- address %IP4Addr; #REQUIRED>
-
- <!ELEMENT strict (hop)+>
- <!ATTLIST strict
- copied CDATA #FIXED "1"
- class CDATA #FIXED "0"
- number CDATA #FIXED "9"
- length %Digits; #REQUIRED
- pointer %Digits; #REQUIRED>
-
- <!ELEMENT record (hop)+>
- <!ATTLIST record
- copied CDATA #FIXED "0"
- class CDATA #FIXED "0"
- number CDATA #FIXED "7"
- length %Digits; #REQUIRED
- pointer %Digits; #REQUIRED>
-
- <!ELEMENT stream EMPTY>
- <!-- 0 <= id <= 65,535 -->
- <!ATTLIST stream
- copied CDATA #FIXED "1"
- class CDATA #FIXED "0"
- number CDATA #FIXED "8"
- length CDATA #FIXED "4"
- id %Digits; #REQUIRED>
-
- <!ELEMENT timestamp (tstamp)+>
- <!-- 0 <= oflw <=15 -->
-
-
-
-Kennedy Informational [Page 10]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
- <!ATTLIST timestamp
- copied CDATA #FIXED "0"
- class CDATA #FIXED "2"
- number CDATA #FIXED "4"
- length %Digits; #REQUIRED
- pointer %Digits; #REQUIRED
- oflw %Digits; #REQUIRED
- flag (0 | 1 | 3) #REQUIRED>
-
- <!ELEMENT tstamp EMPTY>
- <!ATTLIST tstamp
- time %Digits; #REQUIRED
- address %IP4Addr; #IMPLIED>
- <!--
- padding to bring header to 32-bit boundary.
- pad MUST be "0"*
- -->
- <!ELEMENT padding EMPTY>
- <!ATTLIST padding
- pad CDATA #REQUIRED>
-
- <!-- payload MUST be encoded as base-64 [RFC2045], as modified
- by section 2.1 of this RFC -->
- <!ELEMENT payload (CDATA)>
-
-7.2. TCPoXML DTD
-
- <!--
- DTD for TCP over XML.
- Refer to this DTD as:
-
- <!DOCTYPE tcp PUBLIC "-//IETF//DTD BLOAT 1.0 TCP//EN" "bloat.dtd">
- -->
-
- <!-- the pseudoheader is only included for checksum calculations -->
- <!ELEMENT tcp (tcp.pseudoheader?, tcp.header, payload)>
-
- <!ELEMENT tcp.header (src, dest, sequence, acknowledgement, offset,
- reserved, control, window, checksum, urgent,
- tcp.options, padding)>
-
- <!ELEMENT src EMPTY>
- <!-- 0 <= port <= 65,535 -->
- <!ATTLIST src
- port %Digits; #REQUIRED>
-
- <!ELEMENT dest EMPTY>
- <!-- 0 <= port <= 65,535 -->
-
-
-
-Kennedy Informational [Page 11]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
- <!ATTLIST dest
- port %Digits; #REQUIRED>
-
- <!ELEMENT sequence EMPTY>
- <!-- 0 <= number <= 4294967295 -->
- <!ATTLIST sequence
- number %Digits; #REQUIRED>
-
- <!ELEMENT acknowledgement EMPTY>
- <!-- 0 <= number <= 4294967295 -->
- <!ATTLIST acknowledgement
- number %Digits; #REQUIRED>
-
- <!ELEMENT offset EMPTY>
- <!-- 0 <= number <= 255 -->
- <!ATTLIST offset
- number %Digits; #REQUIRED>
-
- <!ELEMENT reserved EMPTY>
- <!ATTLIST reserved
- value CDATA #FIXED "0">
-
- <!ELEMENT control EMPTY>
- <!ATTLIST control
- urg (0|1) #IMPLIED
- ack (0|1) #IMPLIED
- psh (0|1) #IMPLIED
- rst (0|1) #IMPLIED
- syn (0|1) #IMPLIED
- fin (0|1) #IMPLIED>
-
- <!ELEMENT window EMPTY>
- <!-- 0 <= size <= 65,535 -->
- <!ATTLIST window
- size %Digits; #REQUIRED>
-
- <!--
- checksum as in ip, but with
- the following pseudo-header added into the tcp element:
- -->
- <!ELEMENT tcp.pseudoheader (source, destination, protocol,
- tcp.length)>
-
- <!--
- tcp header + data length in octets. does not include the size of
-
- the pseudoheader.
- -->
-
-
-
-Kennedy Informational [Page 12]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
- <!ELEMENT tcp.length EMPTY>
- <!ATTLIST tcp.length
- value %Digits; #REQUIRED>
-
- <!ELEMENT urgent EMPTY>
- <!-- 0 <= pointer <= 65,535 -->
- <!ATTLIST urgent
- pointer %Digits; #REQUIRED>
-
- <!ELEMENT tcp.options (tcp.end | tcp.noop | tcp.mss)+>
-
- <!ELEMENT tcp.end EMPTY>
- <!ATTLIST tcp.end
- kind CDATA #FIXED "0">
-
- <!ELEMENT tcp.noop EMPTY>
- <!ATTLIST tcp.noop
- kind CDATA #FIXED "1">
-
- <!ELEMENT tcp.mss EMPTY>
- <!ATTLIST tcp.mss
- kind CDATA #FIXED "2"
- length CDATA #FIXED "4"
- size %Digits; #REQUIRED>
-
-7.3. UDPoXML DTD
-
- <!--
- DTD for UDP over XML.
- Refer to this DTD as:
-
- <!DOCTYPE udp PUBLIC "-//IETF//DTD BLOAT 1.0 UDP//EN" "bloat.dtd">
- -->
-
- <!ELEMENT udp (udp.pseudoheader?, udp.header, payload)>
-
- <!ELEMENT udp.header (src, dest, udp.length, checksum)>
-
- <!ELEMENT udp.pseudoheader (source, destination, protocol,
- udp.length)>
-
- <!--
- udp header + data length in octets. does not include the size of
- the pseudoheader.
- -->
- <!ELEMENT udp.length EMPTY>
- <!ATTLIST udp.length
- value %Digits; #REQUIRED>
-
-
-
-Kennedy Informational [Page 13]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
-8. Security Considerations
-
- XML, as a subset of SGML, has the same security considerations as
- specified in SGML Media Types [RFC1874]. Security considerations
- that apply to IP, TCP and UDP also likely apply to BLOAT as it does
- not attempt to correct for issues not related to message format.
-
-9. References
-
- [JABBER] Miller, J., "Jabber", draft-miller-jabber-00.txt,
- February 2002. (Work in Progress)
-
- [RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768,
- August 1980.
-
- [RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791,
- September 1981.
-
- [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC
- 793, September 1981.
-
- [RFC894] Hornig, C., "Standard for the Transmission of IP
- Datagrams over Ethernet Networks.", RFC 894, April 1984.
-
- [RFC1042] Postel, J. and J. Reynolds, "Standard for the
- Transmission of IP Datagrams Over IEEE 802 Networks", STD
- 43, RFC 1042, February 1988.
-
- [RFC1123] Braden, R., "Requirements for Internet Hosts -
- Application and Support", RFC 1123, October 1989.
-
- [RFC1874] Levinson, E., "SGML Media Types", RFC 1874, December
- 1995.
-
- [RFC2003] Perkins, C., "IP Encapsulation within IP", RFC 2003,
- October 1996.
-
- [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
- Extensions (MIME) Part One: Format of Internet Message
- Bodies", RFC 2045, November 1996.
-
- [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
- Requirement Levels", BCP 14, RFC 2119, March 1997.
-
- [RFC2279] Yergeau, F., "UTF-8, a transformation format of ISO
- 10646", RFC 2279, January 1998.
-
-
-
-
-
-Kennedy Informational [Page 14]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
- [RFC2460] Deering, S. and R. Hinden, "Internet Protocol, Version 6
- (IPv6) Specification", RFC 2460, December 1998.
-
- [RFC3080] Rose, M., "The Blocks Extensible Exchange Protocol Core",
- RFC 3080, March 2001.
-
- [SOAP] Box, D., Ehnebuske, D., Kakivaya, G., Layman, A.,
- Mendelsohn, N., Nielsen, H. F., Thatte, S. Winer, D.,
- "Simple Object Access Protocol (SOAP) 1.1" World Wide Web
- Consortium Note, May 2000 http://www.w3.org/TR/SOAP/
-
- [XML] Bray, T., Paoli, J., Sperberg-McQueen, C. M., "Extensible
- Markup Language (XML)" World Wide Web Consortium
- Recommendation REC- xml-19980210.
- http://www.w3.org/TR/1998/REC-xml-19980210
-
-10. Author's Address
-
- Hugh Kennedy
- Mimezine
- 1060 West Addison
- Chicago, IL 60613
- USA
-
- EMail: kennedyh@engin.umich.edu
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Kennedy Informational [Page 15]
-
-RFC 3252 Binary Lexical Octet Ad-hoc Transport 1 April 2002
-
-
-11. Full Copyright Statement
-
- Copyright (C) The Internet Society (2002). All Rights Reserved.
-
- This document and translations of it may be copied and furnished to
- others, and derivative works that comment on or otherwise explain it
- or assist in its implementation may be prepared, copied, published
- and distributed, in whole or in part, without restriction of any
- kind, provided that the above copyright notice and this paragraph are
- included on all such copies and derivative works. However, this
- document itself may not be modified in any way, such as by removing
- the copyright notice or references to the Internet Society or other
- Internet organizations, except as needed for the purpose of
- developing Internet standards in which case the procedures for
- copyrights defined in the Internet Standards process must be
- followed, or as required to translate it into languages other than
- English.
-
- The limited permissions granted above are perpetual and will not be
- revoked by the Internet Society or its successors or assigns.
-
- This document and the information contained herein is provided on an
- "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
- TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
- BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
- HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
- MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-
-Acknowledgement
-
- Funding for the RFC Editor function is currently provided by the
- Internet Society.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Kennedy Informational [Page 16]
-
diff --git a/tests/auto/network/access/qftp/tst_qftp.cpp b/tests/auto/network/access/qftp/tst_qftp.cpp
deleted file mode 100644
index 886a589324..0000000000
--- a/tests/auto/network/access/qftp/tst_qftp.cpp
+++ /dev/null
@@ -1,2317 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** 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 The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-
-#include <QtTest/QtTest>
-
-#include <qcoreapplication.h>
-#include <qfile.h>
-#include <qbuffer.h>
-#include "private/qftp_p.h"
-#include <qmap.h>
-#include <time.h>
-#include <stdlib.h>
-#include <QNetworkProxy>
-#include <QTcpServer>
-#include <QHostInfo>
-#include <QElapsedTimer>
-#include <QTcpSocket>
-
-#include "../../../network-settings.h"
-
-template <class T1, class T2>
-static QByteArray msgComparison(T1 lhs, const char *op, T2 rhs)
-{
- QString result;
- QTextStream(&result) << lhs << ' ' << op << ' ' << rhs;
- return result.toLatin1();
-}
-
-class tst_QFtp : public QObject
-{
- Q_OBJECT
-
-public:
- tst_QFtp();
-
-private slots:
- void initTestCase_data();
- void initTestCase();
- void init();
- void cleanup();
- void connectToHost_data();
- void connectToHost();
- void connectToUnresponsiveHost();
- void login_data();
- void login();
- void close_data();
- void close();
-
- void list_data();
- void list();
- void cd_data();
- void cd();
- void get_data();
- void get();
- void put_data();
- void put();
- void mkdir_data();
- void mkdir();
- void mkdir2();
- void rename_data();
- void rename();
-
- void commandSequence_data();
- void commandSequence();
-
- void abort_data();
- void abort();
-
- void bytesAvailable_data();
- void bytesAvailable();
-
- void activeMode();
-
- void proxy_data();
- void proxy();
-
- void binaryAscii();
-
- void doneSignal();
- void queueMoreCommandsInDoneSlot();
-
- void qtbug7359Crash();
-
- void loginURL_data();
- void loginURL();
-
-protected slots:
- void stateChanged( int );
- void listInfo( const QUrlInfo & );
- void readyRead();
- void dataTransferProgress(qint64, qint64);
-
- void commandStarted( int );
- void commandFinished( int, bool );
- void done( bool );
- void activeModeDone( bool );
- void mkdir2Slot(int id, bool error);
- void cdUpSlot(bool);
-
-private:
- QFtp *newFtp();
- void addCommand( QFtp::Command, int );
- bool fileExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &file, const QString &cdDir = QString() );
- bool dirExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &cdDir, const QString &dirToCreate );
-
- void renameInit( const QString &host, const QString &user, const QString &password, const QString &createFile );
- void renameCleanup( const QString &host, const QString &user, const QString &password, const QString &fileToDelete );
-
- QFtp *ftp;
-
- QList<int> ids; // helper to make sure that all expected signals are emitted
- int current_id;
-
- int connectToHost_state;
- int close_state;
- int login_state;
- int cur_state;
- struct CommandResult
- {
- int id;
- int success;
- };
- QMap< QFtp::Command, CommandResult > resultMap;
- typedef QMap<QFtp::Command,CommandResult>::Iterator ResMapIt;
-
- int done_success;
- int commandSequence_success;
-
- qlonglong bytesAvailable_finishedGet;
- qlonglong bytesAvailable_finished;
- qlonglong bytesAvailable_done;
-
- QList<QUrlInfo> listInfo_i;
- QByteArray newData_ba;
- qlonglong bytesTotal;
- qlonglong bytesDone;
-
- bool inFileDirExistsFunction;
-
- QString uniqueExtension;
- QString rfc3252File;
-};
-
-//#define DUMP_SIGNALS
-
-const int bytesTotal_init = -10;
-const int bytesDone_init = -10;
-
-tst_QFtp::tst_QFtp() :
- ftp(0)
-{
-}
-
-void tst_QFtp::initTestCase_data()
-{
- QTest::addColumn<bool>("setProxy");
- QTest::addColumn<int>("proxyType");
-
- QTest::newRow("WithoutProxy") << false << 0;
-#if QT_CONFIG(socks5)
- QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy);
-#endif
- //### doesn't work well yet.
- //QTest::newRow("WithHttpProxy") << true << int(QNetworkProxy::HttpProxy);
-}
-
-void tst_QFtp::initTestCase()
-{
-#if defined(QT_TEST_SERVER)
- QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpServerName(), 21));
- QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121));
- QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080));
- QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128));
-#else
- if (!QtNetworkSettings::verifyTestNetworkSettings())
- QSKIP("No network test server available");
-#endif
- rfc3252File = QFINDTESTDATA("rfc3252.txt");
- QVERIFY(!rfc3252File.isEmpty());
-}
-
-void tst_QFtp::init()
-{
- QFETCH_GLOBAL(bool, setProxy);
- QFETCH_GLOBAL(int, proxyType);
- if (setProxy) {
-#ifndef QT_NO_NETWORKPROXY
- if (proxyType == QNetworkProxy::Socks5Proxy) {
- QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1080));
- } else if (proxyType == QNetworkProxy::HttpProxy) {
- QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3128));
- }
-#else // !QT_NO_NETWORKPROXY
- Q_UNUSED(proxyType);
- QSKIP("No proxy support");
-#endif // QT_NO_NETWORKPROXY
- }
-
- delete ftp;
- ftp = 0;
-
- ids.clear();
- current_id = 0;
-
- resultMap.clear();
- connectToHost_state = -1;
- close_state = -1;
- login_state = -1;
- cur_state = QFtp::Unconnected;
-
- listInfo_i.clear();
- newData_ba = QByteArray();
- bytesTotal = bytesTotal_init;
- bytesDone = bytesDone_init;
-
- done_success = -1;
- commandSequence_success = -1;
-
- bytesAvailable_finishedGet = 1234567890;
- bytesAvailable_finished = 1234567890;
- bytesAvailable_done = 1234567890;
-
- inFileDirExistsFunction = false;
-
- uniqueExtension = QString::number((quintptr)this) + QString::number(QRandomGenerator::global()->generate())
- + QString::number((qulonglong)time(0));
-}
-
-void tst_QFtp::cleanup()
-{
- if (ftp) {
- delete ftp;
- ftp = 0;
- }
- QFETCH_GLOBAL(bool, setProxy);
- if (setProxy) {
-#ifndef QT_NO_NETWORKPROXY
- QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
-#else
- QSKIP("No proxy support");
-#endif
- }
-
- delete ftp;
- ftp = 0;
-}
-
-void tst_QFtp::connectToHost_data()
-{
- QTest::addColumn<QString>("host");
- QTest::addColumn<uint>("port");
- QTest::addColumn<int>("state");
-
- QTest::newRow( "ok01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << (int)QFtp::Connected;
- QTest::newRow( "error01" ) << QtNetworkSettings::ftpServerName() << (uint)2222 << (int)QFtp::Unconnected;
- QTest::newRow( "error02" ) << QString("foo.bar") << (uint)21 << (int)QFtp::Unconnected;
-}
-
-static QByteArray msgTimedOut(const QString &host, quint16 port = 0)
-{
- QByteArray result = "Network operation timed out on " + host.toLatin1();
- if (port) {
- result += ':';
- result += QByteArray::number(port);
- }
- return result;
-}
-
-void tst_QFtp::connectToHost()
-{
- QFETCH( QString, host );
- QFETCH( uint, port );
-
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
-
- QTestEventLoop::instance().enterLoop( 61 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host, port) );
-
- QTEST( connectToHost_state, "state" );
-
- ResMapIt it = resultMap.find( QFtp::ConnectToHost );
- QVERIFY( it != resultMap.end() );
- QFETCH( int, state );
- if ( state == QFtp::Connected ) {
- QCOMPARE( it.value().success, 1 );
- } else {
- QCOMPARE( it.value().success , 0 );
- }
-}
-
-void tst_QFtp::connectToUnresponsiveHost()
-{
- QFETCH_GLOBAL(bool, setProxy);
- if (setProxy)
- QSKIP( "This test takes too long if we test with proxies too");
-
- QString host = "192.0.2.42"; // IP out of TEST-NET, should be unreachable
- uint port = 21;
-
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
-
- qDebug( "About to connect to host that won't reply (this test takes 60 seconds)" );
- QTestEventLoop::instance().enterLoop( 61 );
-#ifdef Q_OS_WIN
- /* On Windows, we do not get a timeout, because Winsock is behaving in a strange way:
- We issue two "WSAConnect()" calls, after the first, as a result we get WSAEWOULDBLOCK,
- after the second, we get WSAEISCONN, which means that the socket is connected, which cannot be.
- However, after some seconds we get a socket error saying that the remote host closed the connection,
- which can neither be. For this test, that would actually enable us to finish before timout, but handling that case
- (in void QFtpPI::error(QAbstractSocket::SocketError e)) breaks
- a lot of other stuff in QFtp, so we just expect this test to fail on Windows.
- */
- QEXPECT_FAIL("", "timeout not working due to strange Windows socket behaviour (see source file of this test for explanation)", Abort);
-
-#endif
- QVERIFY2(! QTestEventLoop::instance().timeout(), "Network timeout longer than expected (should have been 60 seconds)");
-
- QCOMPARE( ftp->state(), QFtp::Unconnected);
- ResMapIt it = resultMap.find( QFtp::ConnectToHost );
- QVERIFY( it != resultMap.end() );
- QCOMPARE( it.value().success, 0 );
-
- delete ftp;
- ftp = 0;
-}
-
-void tst_QFtp::login_data()
-{
- QTest::addColumn<QString>("host");
- QTest::addColumn<uint>("port");
- QTest::addColumn<QString>("user");
- QTest::addColumn<QString>("password");
- QTest::addColumn<int>("success");
-
- QTest::newRow( "ok01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << 1;
- QTest::newRow( "ok02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString("") << 1;
- QTest::newRow( "ok03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString("foo") << 1;
- QTest::newRow( "ok04" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << 1;
-
- QTest::newRow( "error01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("foo") << QString("") << 0;
- QTest::newRow( "error02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("foo") << QString("bar") << 0;
-}
-
-void tst_QFtp::login()
-{
- QFETCH( QString, host );
- QFETCH( uint, port );
- QFETCH( QString, user );
- QFETCH( QString, password );
-
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
-
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host, port) );
-
- ResMapIt it = resultMap.find( QFtp::Login );
- QVERIFY( it != resultMap.end() );
- QTEST( it.value().success, "success" );
-
- const QFtp::State loginState = static_cast<QFtp::State>(login_state);
- if ( it.value().success ) {
- QCOMPARE( loginState, QFtp::LoggedIn );
- } else {
- QVERIFY2( loginState != QFtp::LoggedIn, msgComparison(loginState, "!=", QFtp::LoggedIn));
- }
-}
-
-void tst_QFtp::close_data()
-{
- QTest::addColumn<QString>("host");
- QTest::addColumn<uint>("port");
- QTest::addColumn<QString>("user");
- QTest::addColumn<QString>("password");
- QTest::addColumn<bool>("login");
-
- QTest::newRow( "login01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << true;
- QTest::newRow( "login02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString() << true;
- QTest::newRow( "login03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftp") << QString("foo") << true;
- QTest::newRow( "login04" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << true;
-
- QTest::newRow( "no-login01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("") << QString("") << false;
-}
-
-void tst_QFtp::close()
-{
- QFETCH( QString, host );
- QFETCH( uint, port );
- QFETCH( QString, user );
- QFETCH( QString, password );
- QFETCH( bool, login );
-
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- if ( login )
- addCommand( QFtp::Login, ftp->login( user, password ) );
- addCommand( QFtp::Close, ftp->close() );
-
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host, port) );
-
- QCOMPARE( close_state, (int)QFtp::Unconnected );
-
- ResMapIt it = resultMap.find( QFtp::Close );
- QVERIFY( it != resultMap.end() );
- QCOMPARE( it.value().success, 1 );
-}
-
-void tst_QFtp::list_data()
-{
- QTest::addColumn<QString>("host");
- QTest::addColumn<uint>("port");
- QTest::addColumn<QString>("user");
- QTest::addColumn<QString>("password");
- QTest::addColumn<QString>("dir");
- QTest::addColumn<int>("success");
- QTest::addColumn<QStringList>("entryNames"); // ### we should rather use a QList<QUrlInfo> here
-
- QStringList flukeRoot;
- flukeRoot << "pub";
- flukeRoot << "qtest";
- QStringList flukeQtest;
- flukeQtest << "bigfile";
- flukeQtest << "nonASCII";
- flukeQtest << "rfc3252";
- flukeQtest << "rfc3252.txt";
- flukeQtest << "upload";
-
- QTest::newRow( "workDir01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString() << 1 << flukeRoot;
- QTest::newRow( "workDir02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString() << 1 << flukeRoot;
-
- QTest::newRow( "relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest;
- QTest::newRow( "relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest;
-
- QTest::newRow( "absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest;
- QTest::newRow( "absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest;
-
- QTest::newRow( "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 1 << QStringList();
- QTest::newRow( "nonExist02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << 1 << QStringList();
- // ### The microsoft server does not seem to work properly at the moment --
- // I am also not able to open a data connection with other, non-Qt FTP
- // clients to it.
- // QTest::newRow( "nonExist03" ) << "ftp.microsoft.com" << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList();
-
- QStringList susePub;
- susePub << "README.mirror-policy" << "axp" << "i386" << "ia64" << "install" << "noarch" << "pubring.gpg-build.suse.de" << "update" << "x86_64";
- QTest::newRow( "epsvNotSupported" ) << QString("ftp.funet.fi") << (uint)21 << QString::fromLatin1("ftp") << QString::fromLatin1("root@") << QString("/pub/Linux/suse/suse") << 1 << susePub;
-}
-
-void tst_QFtp::list()
-{
- QFETCH( QString, host );
- QFETCH( uint, port );
- QFETCH( QString, user );
- QFETCH( QString, password );
- QFETCH( QString, dir );
-
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- addCommand( QFtp::List, ftp->list( dir ) );
- addCommand( QFtp::Close, ftp->close() );
-
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host, port) );
-
- ResMapIt it = resultMap.find( QFtp::List );
- QVERIFY( it != resultMap.end() );
- QTEST( it.value().success, "success" );
- QFETCH( QStringList, entryNames );
- QCOMPARE( listInfo_i.count(), entryNames.count() );
- for ( uint i=0; i < (uint) entryNames.count(); i++ ) {
- QCOMPARE( listInfo_i[i].name(), entryNames[i] );
- }
-}
-
-void tst_QFtp::cd_data()
-{
- QTest::addColumn<QString>("host");
- QTest::addColumn<uint>("port");
- QTest::addColumn<QString>("user");
- QTest::addColumn<QString>("password");
- QTest::addColumn<QString>("dir");
- QTest::addColumn<int>("success");
- QTest::addColumn<QStringList>("entryNames"); // ### we should rather use a QList<QUrlInfo> here
-
- QStringList flukeRoot;
- flukeRoot << "qtest";
- QStringList flukeQtest;
- flukeQtest << "bigfile";
- flukeQtest << "nonASCII";
- flukeQtest << "rfc3252";
- flukeQtest << "rfc3252.txt";
- flukeQtest << "upload";
-
- QTest::newRow( "relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest;
- QTest::newRow( "relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest;
-
- QTest::newRow( "absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest;
- QTest::newRow( "absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest;
-
- QTest::newRow( "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 0 << QStringList();
- QTest::newRow( "nonExist03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList();
-}
-
-void tst_QFtp::cd()
-{
- QFETCH( QString, host );
- QFETCH( uint, port );
- QFETCH( QString, user );
- QFETCH( QString, password );
- QFETCH( QString, dir );
-
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- addCommand( QFtp::Cd, ftp->cd( dir ) );
- addCommand( QFtp::List, ftp->list() );
- addCommand( QFtp::Close, ftp->close() );
-
- QTestEventLoop::instance().enterLoop( 30 );
-
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() ) {
- QFAIL( msgTimedOut(host, port) );
- }
-
- ResMapIt it = resultMap.find( QFtp::Cd );
- QVERIFY( it != resultMap.end() );
- QTEST( it.value().success, "success" );
- QFETCH( QStringList, entryNames );
- QCOMPARE( listInfo_i.count(), entryNames.count() );
- for ( uint i=0; i < (uint) entryNames.count(); i++ ) {
- QCOMPARE( listInfo_i[i].name(), entryNames[i] );
- }
-}
-
-void tst_QFtp::get_data()
-{
- QTest::addColumn<QString>("host");
- QTest::addColumn<uint>("port");
- QTest::addColumn<QString>("user");
- QTest::addColumn<QString>("password");
- QTest::addColumn<QString>("file");
- QTest::addColumn<int>("success");
- QTest::addColumn<QByteArray>("res");
- QTest::addColumn<bool>("useIODevice");
-
- // ### move this into external testdata
- QFile file(rfc3252File);
- QVERIFY2( file.open( QIODevice::ReadOnly ), qPrintable(file.errorString()) );
- QByteArray rfc3252 = file.readAll();
-
- // test the two get() overloads in one routine
- for ( int i=0; i<2; i++ ) {
- const QByteArray iB = QByteArray::number(i);
- QTest::newRow(("relPath01_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
- << "qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1);
- QTest::newRow(("relPath02_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
- << "qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1);
-
- QTest::newRow(("absPath01_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
- << "/qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1);
- QTest::newRow(("absPath02_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
- << "/var/ftp/qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1);
-
- QTest::newRow(("nonExist01_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
- << QString("foo") << 0 << QByteArray() << (bool)(i==1);
- QTest::newRow(("nonExist02_" + iB).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
- << QString("/foo") << 0 << QByteArray() << (bool)(i==1);
- }
-}
-
-void tst_QFtp::get()
-{
- // for the overload that takes a QIODevice
- QByteArray buf_ba;
- QBuffer buf( &buf_ba );
-
- QFETCH( QString, host );
- QFETCH( uint, port );
- QFETCH( QString, user );
- QFETCH( QString, password );
- QFETCH( QString, file );
- QFETCH( bool, useIODevice );
-
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- if ( useIODevice ) {
- buf.open( QIODevice::WriteOnly );
- addCommand( QFtp::Get, ftp->get( file, &buf ) );
- } else {
- addCommand( QFtp::Get, ftp->get( file ) );
- }
- addCommand( QFtp::Close, ftp->close() );
-
- QTestEventLoop::instance().enterLoop( 50 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host, port) );
-
- ResMapIt it = resultMap.find( QFtp::Get );
- QVERIFY( it != resultMap.end() );
- QTEST( it.value().success, "success" );
- if ( useIODevice ) {
- QTEST( buf_ba, "res" );
- } else {
- QTEST( newData_ba, "res" );
- }
- QVERIFY2( bytesTotal != bytesTotal_init, msgComparison(bytesTotal, "!=", bytesTotal_init) );
- if ( bytesTotal != -1 ) {
- QCOMPARE( bytesDone, bytesTotal );
- }
- if ( useIODevice ) {
- if ( bytesDone != bytesDone_init ) {
- QCOMPARE( qlonglong(buf_ba.size()), bytesDone );
- }
- } else {
- if ( bytesDone != bytesDone_init ) {
- QCOMPARE( qlonglong(newData_ba.size()), bytesDone );
- }
- }
-}
-
-void tst_QFtp::put_data()
-{
- QTest::addColumn<QString>("host");
- QTest::addColumn<uint>("port");
- QTest::addColumn<QString>("user");
- QTest::addColumn<QString>("password");
- QTest::addColumn<QString>("file");
- QTest::addColumn<QByteArray>("fileData");
- QTest::addColumn<bool>("useIODevice");
- QTest::addColumn<int>("success");
-
- // ### move this into external testdata
- QFile file(rfc3252File);
- QVERIFY2( file.open( QIODevice::ReadOnly ), qPrintable(file.errorString()) );
- QByteArray rfc3252 = file.readAll();
-
- QByteArray bigData( 10*1024*1024, 0 );
- bigData.fill( 'A' );
-
- // test the two put() overloads in one routine with a file name containing
- // U+0x00FC (latin small letter u with diaeresis) for QTBUG-52303, testing UTF-8
- for ( int i=0; i<2; i++ ) {
- QTest::newRow(("relPath01_" + QByteArray::number(i)).constData()) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
- << (QLatin1String("qtest/upload/rel01_") + QChar(0xfc) + QLatin1String("%1")) << rfc3252
- << (bool)(i==1) << 1;
- /*
- QTest::newRow( QString("relPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
- << QString("qtest/upload/rel02_%1") << rfc3252
- << (bool)(i==1) << 1;
- QTest::newRow( QString("relPath03_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
- << QString("qtest/upload/rel03_%1") << QByteArray()
- << (bool)(i==1) << 1;
- QTest::newRow( QString("relPath04_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
- << QString("qtest/upload/rel04_%1") << bigData
- << (bool)(i==1) << 1;
-
- QTest::newRow( QString("absPath01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
- << QString("/qtest/upload/abs01_%1") << rfc3252
- << (bool)(i==1) << 1;
- QTest::newRow( QString("absPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
- << QString("/srv/ftp/qtest/upload/abs02_%1") << rfc3252
- << (bool)(i==1) << 1;
-
- QTest::newRow( QString("nonExist01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
- << QString("foo") << QByteArray()
- << (bool)(i==1) << 0;
- QTest::newRow( QString("nonExist02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
- << QString("/foo") << QByteArray()
- << (bool)(i==1) << 0;
-*/
- }
-}
-
-void tst_QFtp::put()
-{
- QFETCH( QString, host );
- QFETCH( uint, port );
- QFETCH( QString, user );
- QFETCH( QString, password );
- QFETCH( QString, file );
- QFETCH( QByteArray, fileData );
- QFETCH( bool, useIODevice );
-
-#if defined(Q_OS_WIN) && !defined(QT_NO_NETWORKPROXY)
- QFETCH_GLOBAL(bool, setProxy);
- if (setProxy) {
- QFETCH_GLOBAL(int, proxyType);
- if (proxyType == QNetworkProxy::Socks5Proxy)
- QSKIP("With socks5 the put() test takes too long time on Windows.");
- }
-#endif // OS_WIN && !QT_NO_NETWORKPROXY
-
- const int timestep = 50;
-
- if(file.contains('%'))
- file = file.arg(uniqueExtension);
-
- // for the overload that takes a QIODevice
- QBuffer buf_fileData( &fileData );
- buf_fileData.open( QIODevice::ReadOnly );
-
- ResMapIt it;
- //////////////////////////////////////////////////////////////////
- // upload the file
- init();
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- if ( useIODevice )
- addCommand( QFtp::Put, ftp->put( &buf_fileData, file ) );
- else
- addCommand( QFtp::Put, ftp->put( fileData, file ) );
- addCommand( QFtp::Close, ftp->close() );
-
- for(int time = 0; time <= fileData.length() / 20000; time += timestep) {
- QTestEventLoop::instance().enterLoop( timestep );
- if(ftp->currentCommand() == QFtp::None)
- break;
- }
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host, port) );
-
- it = resultMap.find( QFtp::Put );
- QVERIFY( it != resultMap.end() );
- QTEST( it.value().success, "success" );
- if ( !it.value().success ) {
- QVERIFY( !fileExists( host, port, user, password, file ) );
- return; // the following tests are only meaningful if the file could be put
- }
- QCOMPARE( bytesTotal, qlonglong(fileData.size()) );
- QCOMPARE( bytesDone, bytesTotal );
-
- QVERIFY( fileExists( host, port, user, password, file ) );
-
- //////////////////////////////////////////////////////////////////
- // fetch file to make sure that it is equal to the uploaded file
- init();
- ftp = newFtp();
- QBuffer buf;
- buf.open( QIODevice::WriteOnly );
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- addCommand( QFtp::Get, ftp->get( file, &buf ) );
- addCommand( QFtp::Close, ftp->close() );
-
- for(int time = 0; time <= fileData.length() / 20000; time += timestep) {
- QTestEventLoop::instance().enterLoop( timestep );
- if(ftp->currentCommand() == QFtp::None)
- break;
- }
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host, port) );
-
- QCOMPARE( done_success, 1 );
- QTEST( buf.buffer(), "fileData" );
-
- //////////////////////////////////////////////////////////////////
- // cleanup (i.e. remove the file) -- this also tests the remove command
- init();
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- addCommand( QFtp::Remove, ftp->remove( file ) );
- addCommand( QFtp::Close, ftp->close() );
-
- QTestEventLoop::instance().enterLoop( timestep );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host, port) );
-
- it = resultMap.find( QFtp::Remove );
- QVERIFY( it != resultMap.end() );
- QCOMPARE( it.value().success, 1 );
-
- QVERIFY( !fileExists( host, port, user, password, file ) );
-}
-
-void tst_QFtp::mkdir_data()
-{
- QTest::addColumn<QString>("host");
- QTest::addColumn<uint>("port");
- QTest::addColumn<QString>("user");
- QTest::addColumn<QString>("password");
- QTest::addColumn<QString>("cdDir");
- QTest::addColumn<QString>("dirToCreate");
- QTest::addColumn<int>("success");
-
- QTest::newRow( "relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
- << "qtest/upload" << QString("rel01_%1") << 1;
- QTest::newRow( "relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
- << "qtest/upload" << QString("rel02_%1") << 1;
- QTest::newRow( "relPath03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
- << "qtest/upload" << QString("rel03_%1") << 1;
-
- QTest::newRow( "absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
- << "." << QString("/qtest/upload/abs01_%1") << 1;
- QTest::newRow( "absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password")
- << "." << QString("/var/ftp/qtest/upload/abs02_%1") << 1;
-
- // QTest::newRow( "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 0;
- QTest::newRow( "nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
- << "." << QString("foo") << 0;
- QTest::newRow( "nonExist02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString()
- << "." << QString("/foo") << 0;
-}
-
-void tst_QFtp::mkdir()
-{
- QFETCH( QString, host );
- QFETCH( uint, port );
- QFETCH( QString, user );
- QFETCH( QString, password );
- QFETCH( QString, cdDir );
- QFETCH( QString, dirToCreate );
-
- if(dirToCreate.contains('%'))
- dirToCreate = dirToCreate.arg(uniqueExtension);
-
- //////////////////////////////////////////////////////////////////
- // create the directory
- init();
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- addCommand( QFtp::Cd, ftp->cd( cdDir ) );
- addCommand( QFtp::Mkdir, ftp->mkdir( dirToCreate ) );
- addCommand( QFtp::Close, ftp->close() );
-
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host, port) );
-
- ResMapIt it = resultMap.find( QFtp::Mkdir );
- QVERIFY( it != resultMap.end() );
- QTEST( it.value().success, "success" );
- if ( !it.value().success ) {
- QVERIFY( !dirExists( host, port, user, password, cdDir, dirToCreate ) );
- return; // the following tests are only meaningful if the dir could be created
- }
- QVERIFY( dirExists( host, port, user, password, cdDir, dirToCreate ) );
-
- //////////////////////////////////////////////////////////////////
- // create the directory again (should always fail!)
- init();
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- addCommand( QFtp::Cd, ftp->cd( cdDir ) );
- addCommand( QFtp::Mkdir, ftp->mkdir( dirToCreate ) );
- addCommand( QFtp::Close, ftp->close() );
-
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host, port) );
-
- it = resultMap.find( QFtp::Mkdir );
- QVERIFY( it != resultMap.end() );
- QCOMPARE( it.value().success, 0 );
-
- //////////////////////////////////////////////////////////////////
- // remove the directory
- init();
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- addCommand( QFtp::Cd, ftp->cd( cdDir ) );
- addCommand( QFtp::Rmdir, ftp->rmdir( dirToCreate ) );
- addCommand( QFtp::Close, ftp->close() );
-
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host, port) );
-
- it = resultMap.find( QFtp::Rmdir );
- QVERIFY( it != resultMap.end() );
- QCOMPARE( it.value().success, 1 );
-
- QVERIFY( !dirExists( host, port, user, password, cdDir, dirToCreate ) );
-}
-
-void tst_QFtp::mkdir2()
-{
- ftp = new QFtp;
- ftp->connectToHost(QtNetworkSettings::ftpServerName());
- ftp->login();
- current_id = ftp->cd("kake/test");
-
- QEventLoop loop;
- connect(ftp, SIGNAL(done(bool)), &loop, SLOT(quit()));
- connect(ftp, SIGNAL(commandFinished(int,bool)), this, SLOT(mkdir2Slot(int,bool)));
- QTimer::singleShot(5000, &loop, SLOT(quit()));
-
- QSignalSpy commandStartedSpy(ftp, SIGNAL(commandStarted(int)));
- QSignalSpy commandFinishedSpy(ftp, SIGNAL(commandFinished(int,bool)));
-
- loop.exec();
-
- QCOMPARE(commandStartedSpy.count(), 4); // connect, login, cd, mkdir
- QCOMPARE(commandFinishedSpy.count(), 4);
-
- for (int i = 0; i < 4; ++i)
- QCOMPARE(commandFinishedSpy.at(i).at(0), commandStartedSpy.at(i).at(0));
-
- QVERIFY(!commandFinishedSpy.at(0).at(1).toBool());
- QVERIFY(!commandFinishedSpy.at(1).at(1).toBool());
- QVERIFY(commandFinishedSpy.at(2).at(1).toBool());
- QVERIFY(commandFinishedSpy.at(3).at(1).toBool());
-
- delete ftp;
- ftp = 0;
-}
-
-void tst_QFtp::mkdir2Slot(int id, bool)
-{
- if (id == current_id)
- ftp->mkdir("kake/test");
-}
-
-void tst_QFtp::rename_data()
-{
- QTest::addColumn<QString>("host");
- QTest::addColumn<QString>("user");
- QTest::addColumn<QString>("password");
- QTest::addColumn<QString>("cdDir");
- QTest::addColumn<QString>("oldfile");
- QTest::addColumn<QString>("newfile");
- QTest::addColumn<QString>("createFile");
- QTest::addColumn<QString>("renamedFile");
- QTest::addColumn<int>("success");
-
- QTest::newRow("relPath01") << QtNetworkSettings::ftpServerName() << QString() << QString()
- << "qtest/upload"
- << QString("rel_old01_%1") << QString("rel_new01_%1")
- << QString("qtest/upload/rel_old01_%1") << QString("qtest/upload/rel_new01_%1")
- << 1;
- QTest::newRow("relPath02") << QtNetworkSettings::ftpServerName() << QString("ftptest") << "password"
- << "qtest/upload"
- << QString("rel_old02_%1") << QString("rel_new02_%1")
- << QString("qtest/upload/rel_old02_%1") << QString("qtest/upload/rel_new02_%1")
- << 1;
- QTest::newRow("relPath03") << QtNetworkSettings::ftpServerName() << QString("ftptest") << "password"
- << "qtest/upload"
- << QString("rel_old03_%1")<< QString("rel_new03_%1")
- << QString("qtest/upload/rel_old03_%1") << QString("qtest/upload/rel_new03_%1")
- << 1;
-
- QTest::newRow("absPath01") << QtNetworkSettings::ftpServerName() << QString() << QString()
- << QString()
- << QString("/qtest/upload/abs_old01_%1") << QString("/qtest/upload/abs_new01_%1")
- << QString("/qtest/upload/abs_old01_%1") << QString("/qtest/upload/abs_new01_%1")
- << 1;
- QTest::newRow("absPath02") << QtNetworkSettings::ftpServerName() << QString("ftptest") << "password"
- << QString()
- << QString("/var/ftp/qtest/upload/abs_old02_%1") << QString("/var/ftp/qtest/upload/abs_new02_%1")
- << QString("/var/ftp/qtest/upload/abs_old02_%1") << QString("/var/ftp/qtest/upload/abs_new02_%1")
- << 1;
-
- QTest::newRow("nonExist01") << QtNetworkSettings::ftpServerName() << QString() << QString()
- << QString()
- << QString("foo") << "new_foo"
- << QString() << QString()
- << 0;
- QTest::newRow("nonExist02") << QtNetworkSettings::ftpServerName() << QString() << QString()
- << QString()
- << QString("/foo") << QString("/new_foo")
- << QString() << QString()
- << 0;
-}
-
-void tst_QFtp::renameInit( const QString &host, const QString &user, const QString &password, const QString &createFile )
-{
- if ( !createFile.isNull() ) {
- // upload the file
- init();
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- addCommand( QFtp::Put, ftp->put( QByteArray(), createFile ) );
- addCommand( QFtp::Close, ftp->close() );
-
- QTestEventLoop::instance().enterLoop( 50 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host) );
-
- ResMapIt it = resultMap.find( QFtp::Put );
- QVERIFY( it != resultMap.end() );
- QCOMPARE( it.value().success, 1 );
-
- QVERIFY( fileExists( host, 21, user, password, createFile ) );
- }
-}
-
-void tst_QFtp::renameCleanup( const QString &host, const QString &user, const QString &password, const QString &fileToDelete )
-{
- if ( !fileToDelete.isNull() ) {
- // cleanup (i.e. remove the file)
- init();
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- addCommand( QFtp::Remove, ftp->remove( fileToDelete ) );
- addCommand( QFtp::Close, ftp->close() );
-
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host) );
-
- ResMapIt it = resultMap.find( QFtp::Remove );
- QVERIFY( it != resultMap.end() );
- QCOMPARE( it.value().success, 1 );
-
- QVERIFY( !fileExists( host, 21, user, password, fileToDelete ) );
- }
-}
-
-void tst_QFtp::rename()
-{
- QFETCH( QString, host );
- QFETCH( QString, user );
- QFETCH( QString, password );
- QFETCH( QString, cdDir );
- QFETCH( QString, oldfile );
- QFETCH( QString, newfile );
- QFETCH( QString, createFile );
- QFETCH( QString, renamedFile );
-
- if(oldfile.contains('%'))
- oldfile = oldfile.arg(uniqueExtension);
- if(newfile.contains('%'))
- newfile = newfile.arg(uniqueExtension);
- if(createFile.contains('%'))
- createFile = createFile.arg(uniqueExtension);
- if(renamedFile.contains('%'))
- renamedFile = renamedFile.arg(uniqueExtension);
-
- renameInit( host, user, password, createFile );
-
- init();
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- if ( !cdDir.isNull() )
- addCommand( QFtp::Cd, ftp->cd( cdDir ) );
- addCommand( QFtp::Rename, ftp->rename( oldfile, newfile ) );
- addCommand( QFtp::Close, ftp->close() );
-
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host) );
-
- ResMapIt it = resultMap.find( QFtp::Rename );
- QVERIFY( it != resultMap.end() );
- QTEST( it.value().success, "success" );
-
- if ( it.value().success ) {
- QVERIFY( !fileExists( host, 21, user, password, oldfile, cdDir ) );
- QVERIFY( fileExists( host, 21, user, password, newfile, cdDir ) );
- QVERIFY( fileExists( host, 21, user, password, renamedFile ) );
- } else {
- QVERIFY( !fileExists( host, 21, user, password, newfile, cdDir ) );
- QVERIFY( !fileExists( host, 21, user, password, renamedFile ) );
- }
-
- renameCleanup( host, user, password, renamedFile );
-}
-
-/*
- The commandSequence() test does not test any particular function. It rather
- tests a sequence of arbitrary commands specified in the test data.
-*/
-class FtpCommand
-{
-public:
- FtpCommand() :
- cmd(QFtp::None)
- { }
-
- FtpCommand( QFtp::Command command ) :
- cmd(command)
- { }
-
- FtpCommand( QFtp::Command command, const QStringList &arguments ) :
- cmd(command), args(arguments)
- { }
-
- FtpCommand( const FtpCommand &c )
- { *this = c; }
-
- FtpCommand &operator=( const FtpCommand &c )
- {
- this->cmd = c.cmd;
- this->args = c.args;
- return *this;
- }
-
- QFtp::Command cmd;
- QStringList args;
-};
-QDataStream &operator<<( QDataStream &s, const FtpCommand &command )
-{
- s << (int)command.cmd;
- s << command.args;
- return s;
-}
-QDataStream &operator>>( QDataStream &s, FtpCommand &command )
-{
- int tmp;
- s >> tmp;
- command.cmd = (QFtp::Command)tmp;
- s >> command.args;
- return s;
-}
-Q_DECLARE_METATYPE(QList<FtpCommand>)
-
-void tst_QFtp::commandSequence_data()
-{
- // some "constants"
- QStringList argConnectToHost01;
- argConnectToHost01 << QtNetworkSettings::ftpServerName() << "21";
-
- QStringList argLogin01, argLogin02, argLogin03, argLogin04;
- argLogin01 << QString() << QString();
- argLogin02 << "ftp" << QString();
- argLogin03 << "ftp" << "foo";
- argLogin04 << QString("ftptest") << "password";
-
- FtpCommand connectToHost01( QFtp::ConnectToHost, argConnectToHost01 );
- FtpCommand login01( QFtp::Login, argLogin01 );
- FtpCommand login02( QFtp::Login, argLogin01 );
- FtpCommand login03( QFtp::Login, argLogin01 );
- FtpCommand login04( QFtp::Login, argLogin01 );
- FtpCommand close01( QFtp::Close );
-
- QTest::addColumn<QList<FtpCommand> >("cmds");
- QTest::addColumn<int>("success");
-
- // success data
- {
- QList<FtpCommand> cmds;
- cmds << connectToHost01;
- QTest::newRow( "simple_ok01" ) << cmds << 1;
- }
- {
- QList<FtpCommand> cmds;
- cmds << connectToHost01;
- cmds << login01;
- QTest::newRow( "simple_ok02" ) << cmds << 1;
- }
- {
- QList<FtpCommand> cmds;
- cmds << connectToHost01;
- cmds << login01;
- cmds << close01;
- QTest::newRow( "simple_ok03" ) << cmds << 1;
- }
- {
- QList<FtpCommand> cmds;
- cmds << connectToHost01;
- cmds << close01;
- QTest::newRow( "simple_ok04" ) << cmds << 1;
- }
- {
- QList<FtpCommand> cmds;
- cmds << connectToHost01;
- cmds << login01;
- cmds << close01;
- cmds << connectToHost01;
- cmds << login02;
- cmds << close01;
- QTest::newRow( "connect_twice" ) << cmds << 1;
- }
-
- // error data
- {
- QList<FtpCommand> cmds;
- cmds << close01;
- QTest::newRow( "error01" ) << cmds << 0;
- }
- {
- QList<FtpCommand> cmds;
- cmds << login01;
- QTest::newRow( "error02" ) << cmds << 0;
- }
- {
- QList<FtpCommand> cmds;
- cmds << login01;
- cmds << close01;
- QTest::newRow( "error03" ) << cmds << 0;
- }
- {
- QList<FtpCommand> cmds;
- cmds << connectToHost01;
- cmds << login01;
- cmds << close01;
- cmds << login01;
- QTest::newRow( "error04" ) << cmds << 0;
- }
-}
-
-void tst_QFtp::commandSequence()
-{
- QFETCH( QList<FtpCommand>, cmds );
-
- ftp = newFtp();
- QString host;
- quint16 port = 0;
- QList<FtpCommand>::iterator it;
- for ( it = cmds.begin(); it != cmds.end(); ++it ) {
- switch ( (*it).cmd ) {
- case QFtp::ConnectToHost:
- {
- QCOMPARE( (*it).args.count(), 2 );
- bool portOk;
- port = (*it).args[1].toUShort( &portOk );
- QVERIFY( portOk );
- host = (*it).args[0];
- ids << ftp->connectToHost( host, port );
- }
- break;
- case QFtp::Login:
- QCOMPARE( (*it).args.count(), 2 );
- ids << ftp->login( (*it).args[0], (*it).args[1] );
- break;
- case QFtp::Close:
- QCOMPARE( (*it).args.count(), 0 );
- ids << ftp->close();
- break;
- default:
- QFAIL( "Error in test: unexpected enum value" );
- break;
- }
- }
-
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host) );
-
- QTEST( commandSequence_success, "success" );
-}
-
-void tst_QFtp::abort_data()
-{
- QTest::addColumn<QString>("host");
- QTest::addColumn<uint>("port");
- QTest::addColumn<QString>("file");
- QTest::addColumn<QByteArray>("uploadData");
-
- QTest::newRow( "get_fluke01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("qtest/bigfile") << QByteArray();
- QTest::newRow( "get_fluke02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("qtest/rfc3252") << QByteArray();
-
- // Qt/CE test environment has too little memory for this test
- QByteArray bigData( 10*1024*1024, 0 );
- bigData.fill( 'B' );
- QTest::newRow( "put_fluke01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("qtest/upload/abort_put") << bigData;
-}
-
-void tst_QFtp::abort()
-{
- QSKIP("This test takes too long.");
- // In case you wonder where the abort() actually happens, look into
- // tst_QFtp::dataTransferProgress
- //
- QFETCH( QString, host );
- QFETCH( uint, port );
- QFETCH( QString, file );
- QFETCH( QByteArray, uploadData );
-
- QFtp::Command cmd;
- if ( uploadData.size() == 0 )
- cmd = QFtp::Get;
- else
- cmd = QFtp::Put;
-
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login() );
- if ( cmd == QFtp::Get )
- addCommand( cmd, ftp->get( file ) );
- else
- addCommand( cmd, ftp->put( uploadData, file ) );
- addCommand( QFtp::Close, ftp->close() );
-
- for(int time = 0; time <= uploadData.length() / 30000; time += 30) {
- QTestEventLoop::instance().enterLoop( 50 );
- if(ftp->currentCommand() == QFtp::None)
- break;
- }
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host, port) );
-
- ResMapIt it = resultMap.find( cmd );
- QVERIFY( it != resultMap.end() );
- // ### how to test the abort?
- if ( it.value().success ) {
- // The FTP server on fluke is sadly returning a success, even when
- // the operation was aborted. So we have to use some heuristics.
- if ( host == QtNetworkSettings::ftpServerName() ) {
- if ( cmd == QFtp::Get ) {
- QVERIFY2(bytesDone <= bytesTotal, msgComparison(bytesDone, "<=", bytesTotal));
- } else {
- // put commands should always be aborted, since we use really
- // big data
- QVERIFY2( bytesDone != bytesTotal, msgComparison(bytesDone, "!=", bytesTotal) );
- }
- } else {
- // this could be tested by verifying that no more progress signals are emitted
- QVERIFY2(bytesDone <= bytesTotal, msgComparison(bytesDone, "<=", bytesTotal));
- }
- } else {
- QVERIFY2( bytesDone != bytesTotal, msgComparison(bytesDone, "!=", bytesTotal) );
- }
-
- if ( cmd == QFtp::Put ) {
- //////////////////////////////////////
- // cleanup (i.e. remove the file)
- init();
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login() );
- addCommand( QFtp::Remove, ftp->remove( file ) );
- addCommand( QFtp::Close, ftp->close() );
-
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host, port) );
-
- it = resultMap.find( QFtp::Remove );
- QVERIFY( it != resultMap.end() );
- QCOMPARE( it.value().success, 1 );
- }
-}
-
-void tst_QFtp::bytesAvailable_data()
-{
- QTest::addColumn<QString>("host");
- QTest::addColumn<QString>("file");
- QTest::addColumn<int>("type");
- QTest::addColumn<qlonglong>("bytesAvailFinishedGet");
- QTest::addColumn<qlonglong>("bytesAvailFinished");
- QTest::addColumn<qlonglong>("bytesAvailDone");
-
- QTest::newRow( "fluke01" ) << QtNetworkSettings::ftpServerName() << QString("qtest/bigfile") << 0 << (qlonglong)519240 << (qlonglong)519240 << (qlonglong)519240;
- QTest::newRow( "fluke02" ) << QtNetworkSettings::ftpServerName() << QString("qtest/rfc3252") << 0 << (qlonglong)25962 << (qlonglong)25962 << (qlonglong)25962;
-
- QTest::newRow( "fluke03" ) << QtNetworkSettings::ftpServerName() << QString("qtest/bigfile") << 1 << (qlonglong)519240 << (qlonglong)0 << (qlonglong)0;
- QTest::newRow( "fluke04" ) << QtNetworkSettings::ftpServerName() << QString("qtest/rfc3252") << 1 << (qlonglong)25962 << (qlonglong)0 << (qlonglong)0;
-}
-
-void tst_QFtp::bytesAvailable()
-{
- QFETCH( QString, host );
- QFETCH( QString, file );
- QFETCH( int, type );
-
- ftp = newFtp();
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) );
- addCommand( QFtp::Login, ftp->login() );
- addCommand( QFtp::Get, ftp->get( file ) );
- if ( type != 0 )
- addCommand( QFtp::Close, ftp->close() );
-
- QTestEventLoop::instance().enterLoop( 40 );
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(host) );
-
- ResMapIt it = resultMap.find( QFtp::Get );
- QVERIFY( it != resultMap.end() );
- QVERIFY( it.value().success );
-
- QFETCH(qlonglong, bytesAvailFinishedGet);
- QCOMPARE(bytesAvailable_finishedGet, bytesAvailFinishedGet);
-
- QFETCH(qlonglong, bytesAvailFinished);
- QCOMPARE(bytesAvailable_finished, bytesAvailFinished);
-
- QFETCH(qlonglong, bytesAvailDone);
- QCOMPARE(bytesAvailable_done, bytesAvailDone);
-
- ftp->readAll();
- QCOMPARE( ftp->bytesAvailable(), 0 );
- delete ftp;
- ftp = 0;
-}
-
-void tst_QFtp::activeMode()
-{
- QFile file("tst_QFtp_activeMode_inittab");
- file.open(QIODevice::ReadWrite);
- QFtp ftp;
- ftp.setTransferMode(QFtp::Active);
- ftp.connectToHost(QtNetworkSettings::ftpServerName(), 21);
- ftp.login();
- ftp.list();
- ftp.get("/qtest/rfc3252.txt", &file);
- connect(&ftp, SIGNAL(done(bool)), SLOT(activeModeDone(bool)));
- QTestEventLoop::instance().enterLoop(900);
- QFile::remove("tst_QFtp_activeMode_inittab");
- QCOMPARE(done_success, 1);
-
-}
-
-void tst_QFtp::activeModeDone(bool error)
-{
- done_success = error ? -1 : 1;
- QTestEventLoop::instance().exitLoop();
-}
-
-void tst_QFtp::proxy_data()
-{
- QTest::addColumn<QString>("host");
- QTest::addColumn<uint>("port");
- QTest::addColumn<QString>("user");
- QTest::addColumn<QString>("password");
- QTest::addColumn<QString>("dir");
- QTest::addColumn<int>("success");
- QTest::addColumn<QStringList>("entryNames"); // ### we should rather use a QList<QUrlInfo> here
-
- QStringList flukeRoot;
- flukeRoot << "qtest";
- QStringList flukeQtest;
- flukeQtest << "bigfile";
- flukeQtest << "nonASCII";
- flukeQtest << "rfc3252";
- flukeQtest << "rfc3252.txt";
- flukeQtest << "upload";
-
- QTest::newRow( "proxy_relPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest;
- QTest::newRow( "proxy_relPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("qtest") << 1 << flukeQtest;
-
- QTest::newRow( "proxy_absPath01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest;
- QTest::newRow( "proxy_absPath02" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString("ftptest") << QString("password") << QString("/var/ftp/qtest") << 1 << flukeQtest;
-
- QTest::newRow( "proxy_nonExist01" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("foo") << 0 << QStringList();
- QTest::newRow( "proxy_nonExist03" ) << QtNetworkSettings::ftpServerName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList();
-}
-
-void tst_QFtp::proxy()
-{
- QFETCH( QString, host );
- QFETCH( uint, port );
- QFETCH( QString, user );
- QFETCH( QString, password );
- QFETCH( QString, dir );
-
- ftp = newFtp();
- addCommand( QFtp::SetProxy, ftp->setProxy( QtNetworkSettings::ftpProxyServerName(), 2121 ) );
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- addCommand( QFtp::Cd, ftp->cd( dir ) );
- addCommand( QFtp::List, ftp->list() );
-
- QTestEventLoop::instance().enterLoop( 50 );
-
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() ) {
- QFAIL( msgTimedOut(host, port) );
- }
-
- ResMapIt it = resultMap.find( QFtp::Cd );
- QVERIFY( it != resultMap.end() );
- QFETCH( int, success );
- QCOMPARE( it.value().success, success );
- QFETCH( QStringList, entryNames );
- QCOMPARE( listInfo_i.count(), entryNames.count() );
- for ( uint i=0; i < (uint) entryNames.count(); i++ ) {
- QCOMPARE( listInfo_i[i].name(), entryNames[i] );
- }
-}
-
-void tst_QFtp::binaryAscii()
-{
- QString file = "asciifile%1.txt";
-
- if(file.contains('%'))
- file = file.arg(uniqueExtension);
-
- QByteArray putData = "a line of text\r\n";
-
- init();
- ftp = newFtp();
- addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::ftpServerName(), 21));
- addCommand(QFtp::Login, ftp->login("ftptest", "password"));
- addCommand(QFtp::Cd, ftp->cd("qtest/upload"));
- addCommand(QFtp::Put, ftp->put(putData, file, QFtp::Ascii));
- addCommand(QFtp::Close, ftp->close());
-
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(QtNetworkSettings::ftpServerName()) );
-
- ResMapIt it = resultMap.find(QFtp::Put);
- QVERIFY(it != resultMap.end());
- QVERIFY(it.value().success);
-
- QByteArray getData;
- QBuffer getBuf(&getData);
- getBuf.open(QBuffer::WriteOnly);
-
- init();
- ftp = newFtp();
- addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::ftpServerName(), 21));
- addCommand(QFtp::Login, ftp->login("ftptest", "password"));
- addCommand(QFtp::Cd, ftp->cd("qtest/upload"));
- addCommand(QFtp::Get, ftp->get(file, &getBuf, QFtp::Binary));
- addCommand(QFtp::Close, ftp->close());
-
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(QtNetworkSettings::ftpServerName()) );
-
- ResMapIt it2 = resultMap.find(QFtp::Get);
- QVERIFY(it2 != resultMap.end());
- QVERIFY(it2.value().success);
- // most modern ftp servers leave the file as it is by default
- // (and do not remove the windows line ending), the -1 below could be
- // deleted in the future
- QCOMPARE(getData.size(), putData.size() - 1);
- //////////////////////////////////////////////////////////////////
- // cleanup (i.e. remove the file) -- this also tests the remove command
- init();
- ftp = newFtp();
- addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::ftpServerName(), 21));
- addCommand(QFtp::Login, ftp->login("ftptest", "password"));
- addCommand(QFtp::Cd, ftp->cd("qtest/upload"));
- addCommand(QFtp::Remove, ftp->remove(file));
- addCommand(QFtp::Close, ftp->close());
-
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() )
- QFAIL( msgTimedOut(QtNetworkSettings::ftpServerName()) );
-
- it = resultMap.find( QFtp::Remove );
- QVERIFY( it != resultMap.end() );
- QCOMPARE( it.value().success, 1 );
-
- QVERIFY(!fileExists(QtNetworkSettings::ftpServerName(), 21, "ftptest", "password", file));
-}
-
-
-// test QFtp::currentId() and QFtp::currentCommand()
-#define CURRENTCOMMAND_TEST \
-{ \
- ResMapIt it; \
- for ( it = resultMap.begin(); it != resultMap.end(); ++it ) { \
- if ( it.value().id == ftp->currentId() ) { \
- QVERIFY( it.key() == ftp->currentCommand() ); \
- } \
-} \
-}
-
-void tst_QFtp::commandStarted( int id )
-{
-#if defined( DUMP_SIGNALS )
- qDebug( "%d:commandStarted( %d )", ftp->currentId(), id );
-#endif
- // make sure that the commandStarted and commandFinished are nested correctly
- QCOMPARE( current_id, 0 );
- current_id = id;
-
- QVERIFY( !ids.isEmpty() );
- QCOMPARE( ids.first(), id );
- if ( ids.count() > 1 ) {
- QVERIFY( ftp->hasPendingCommands() );
- } else {
- QVERIFY( !ftp->hasPendingCommands() );
- }
-
- QVERIFY( ftp->currentId() == id );
- QCOMPARE( cur_state, int(ftp->state()) );
- CURRENTCOMMAND_TEST;
-
- QCOMPARE( ftp->error(), QFtp::NoError );
-}
-
-void tst_QFtp::commandFinished( int id, bool error )
-{
-#if defined( DUMP_SIGNALS )
- qDebug( "%d:commandFinished( %d, %d ) -- errorString: '%s'",
- ftp->currentId(), id, (int)error, ftp->errorString().toLatin1().constData() );
-#endif
- if ( ftp->currentCommand() == QFtp::Get ) {
- bytesAvailable_finishedGet = ftp->bytesAvailable();
- }
- bytesAvailable_finished = ftp->bytesAvailable();
-
- // make sure that the commandStarted and commandFinished are nested correctly
- QCOMPARE( current_id, id );
- current_id = 0;
-
- QVERIFY( !ids.isEmpty() );
- QCOMPARE( ids.first(), id );
- if ( !error && ids.count() > 1) {
- QVERIFY( ftp->hasPendingCommands() );
- } else {
- QVERIFY( !ftp->hasPendingCommands() );
- }
- if ( error ) {
- QVERIFY2( ftp->error() != QFtp::NoError, msgComparison(ftp->error(), "!=", QFtp::NoError) );
- ids.clear();
- } else {
- QCOMPARE( ftp->error(), QFtp::NoError );
- ids.pop_front();
- }
-
- QCOMPARE( ftp->currentId(), id );
- QCOMPARE( cur_state, int(ftp->state()) );
- CURRENTCOMMAND_TEST;
-
- if ( QTest::currentTestFunction() != QLatin1String("commandSequence") ) {
- ResMapIt it = resultMap.find( ftp->currentCommand() );
- QVERIFY( it != resultMap.end() );
- QCOMPARE( it.value().success, -1 );
- if ( error )
- it.value().success = 0;
- else
- it.value().success = 1;
- }
-}
-
-void tst_QFtp::done( bool error )
-{
-#if defined( DUMP_SIGNALS )
- qDebug( "%d:done( %d )", ftp->currentId(), (int)error );
-#endif
- bytesAvailable_done = ftp->bytesAvailable();
-
- QCOMPARE( ftp->currentId(), 0 );
- QVERIFY( current_id == 0 );
- QVERIFY( ids.isEmpty() );
- QVERIFY( cur_state == ftp->state() );
- QVERIFY( !ftp->hasPendingCommands() );
-
- if ( QTest::currentTestFunction() == QLatin1String("commandSequence") ) {
- QCOMPARE( commandSequence_success, -1 );
- if ( error )
- commandSequence_success = 0;
- else
- commandSequence_success = 1;
- }
- QCOMPARE( done_success, -1 );
- if ( error ) {
- QVERIFY2( ftp->error() != QFtp::NoError, msgComparison(ftp->error(), "!=", QFtp::NoError) );
- done_success = 0;
- } else {
- QCOMPARE( ftp->error(), QFtp::NoError );
- done_success = 1;
- }
- QTestEventLoop::instance().exitLoop();
-}
-
-void tst_QFtp::stateChanged( int state )
-{
-#if defined( DUMP_SIGNALS )
- qDebug( "%d: stateChanged( %d )", ftp->currentId(), state );
-#endif
- QCOMPARE( ftp->currentId(), current_id );
- CURRENTCOMMAND_TEST;
-
- QVERIFY2( state != cur_state, msgComparison(state, "!=", cur_state) );
- QCOMPARE( state, (int)ftp->state() );
- if ( state != QFtp::Unconnected ) {
- // make sure that the states are always emitted in the right order (for
- // this, we assume an ordering on the enum values, which they have at
- // the moment)
- QVERIFY2( cur_state < state, msgComparison(cur_state, "<", state) );
-
- // make sure that state changes are only emitted in response to certain
- // commands
- switch ( state ) {
- case QFtp::HostLookup:
- case QFtp::Connecting:
- case QFtp::Connected:
- QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::ConnectToHost );
- break;
- case QFtp::LoggedIn:
- QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::Login );
- break;
- case QFtp::Closing:
- QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::Close );
- break;
- default:
- QWARN( QString("Unexpected state '%1'").arg(state).toLatin1().constData() );
- break;
- }
- }
- cur_state = state;
-
- if ( QTest::currentTestFunction() == QLatin1String("connectToHost") ) {
- switch ( state ) {
- case QFtp::HostLookup:
- case QFtp::Connecting:
- case QFtp::LoggedIn:
- case QFtp::Closing:
- // ignore
- break;
- case QFtp::Connected:
- case QFtp::Unconnected:
- QVERIFY( connectToHost_state == -1 );
- connectToHost_state = state;
- break;
- default:
- QWARN( QString("Unknown state '%1'").arg(state).toLatin1().constData() );
- break;
- }
- } else if ( QTest::currentTestFunction() == QLatin1String("close") ) {
- ResMapIt it = resultMap.find( QFtp::Close );
- if ( it!=resultMap.end() && ftp->currentId()==it.value().id ) {
- if ( state == QFtp::Closing ) {
- QCOMPARE( close_state, -1 );
- close_state = state;
- } else if ( state == QFtp::Unconnected ) {
- QCOMPARE(close_state, int(QFtp::Closing) );
- close_state = state;
- }
- }
- } else if ( QTest::currentTestFunction() == QLatin1String("login") ) {
- ResMapIt it = resultMap.find( QFtp::Login );
- if ( it!=resultMap.end() && ftp->currentId()==it.value().id ) {
- if ( state == QFtp::LoggedIn ) {
- QCOMPARE( login_state, -1 );
- login_state = state;
- }
- }
- }
-}
-
-void tst_QFtp::listInfo( const QUrlInfo &i )
-{
-#if defined( DUMP_SIGNALS )
- qDebug( "%d: listInfo( %s )", ftp->currentId(), i.name().toLatin1().constData() );
-#endif
- QCOMPARE( ftp->currentId(), current_id );
- if ( ids.count() > 1 ) {
- QVERIFY( ftp->hasPendingCommands() );
- } else {
- QVERIFY( !ftp->hasPendingCommands() );
- }
- QCOMPARE( cur_state, int(ftp->state()) );
- CURRENTCOMMAND_TEST;
-
- if ( QTest::currentTestFunction()==QLatin1String("list") || QTest::currentTestFunction()==QLatin1String("cd") || QTest::currentTestFunction()==QLatin1String("proxy") || inFileDirExistsFunction ) {
- ResMapIt it = resultMap.find( QFtp::List );
- QVERIFY( it != resultMap.end() );
- QCOMPARE( ftp->currentId(), it.value().id );
- listInfo_i << i;
- }
-}
-
-void tst_QFtp::readyRead()
-{
-#if defined( DUMP_SIGNALS )
- qDebug( "%d: readyRead(), bytesAvailable == %lu", ftp->currentId(), ftp->bytesAvailable() );
-#endif
- QCOMPARE( ftp->currentId(), current_id );
- if ( ids.count() > 1 ) {
- QVERIFY( ftp->hasPendingCommands() );
- } else {
- QVERIFY( !ftp->hasPendingCommands() );
- }
- QVERIFY( cur_state == ftp->state() );
- CURRENTCOMMAND_TEST;
-
- if ( QTest::currentTestFunction() != QLatin1String("bytesAvailable") ) {
- int oldSize = newData_ba.size();
- qlonglong bytesAvail = ftp->bytesAvailable();
- QByteArray ba = ftp->readAll();
- QCOMPARE( ba.size(), (int) bytesAvail );
- newData_ba.resize( oldSize + ba.size() );
- memcpy( newData_ba.data()+oldSize, ba.data(), ba.size() );
-
- if ( bytesTotal != -1 ) {
- QVERIFY2( (int)newData_ba.size() <= bytesTotal, msgComparison(newData_ba.size(), "<=", bytesTotal) );
- }
- QCOMPARE( qlonglong(newData_ba.size()), bytesDone );
- }
-}
-
-void tst_QFtp::dataTransferProgress( qint64 done, qint64 total )
-{
-#if defined( DUMP_SIGNALS )
- qDebug( "%d: dataTransferProgress( %lli, %lli )", ftp->currentId(), done, total );
-#endif
- QCOMPARE( ftp->currentId(), current_id );
- if ( ids.count() > 1 ) {
- QVERIFY( ftp->hasPendingCommands() );
- } else {
- QVERIFY( !ftp->hasPendingCommands() );
- }
- QCOMPARE( cur_state, int(ftp->state()) );
- CURRENTCOMMAND_TEST;
-
- if ( bytesTotal == bytesTotal_init ) {
- bytesTotal = total;
- } else {
- QCOMPARE( bytesTotal, total );
- }
-
- QVERIFY2( bytesTotal != bytesTotal_init, msgComparison(bytesTotal, "!=", bytesTotal_init) );
- QVERIFY2( bytesDone <= done, msgComparison(bytesDone, "<=", done) );
- bytesDone = done;
- if ( bytesTotal != -1 ) {
- QVERIFY2( bytesDone <= bytesTotal, msgComparison(bytesDone, "<=", bytesTotal) );
- }
-
- if ( QTest::currentTestFunction() == QLatin1String("abort") ) {
- // ### it would be nice if we could specify in our testdata when to do
- // the abort
- if ( done >= total/100000 ) {
- if ( ids.count() != 1 ) {
- // do abort only once
- int tmpId = ids.first();
- ids.clear();
- ids << tmpId;
- ftp->abort();
- }
- }
- }
-}
-
-
-QFtp *tst_QFtp::newFtp()
-{
- QFtp *nFtp = new QFtp( this );
- connect( nFtp, SIGNAL(commandStarted(int)),
- SLOT(commandStarted(int)) );
- connect( nFtp, SIGNAL(commandFinished(int,bool)),
- SLOT(commandFinished(int,bool)) );
- connect( nFtp, SIGNAL(done(bool)),
- SLOT(done(bool)) );
- connect( nFtp, SIGNAL(stateChanged(int)),
- SLOT(stateChanged(int)) );
- connect( nFtp, SIGNAL(listInfo(QUrlInfo)),
- SLOT(listInfo(QUrlInfo)) );
- connect( nFtp, SIGNAL(readyRead()),
- SLOT(readyRead()) );
- connect( nFtp, SIGNAL(dataTransferProgress(qint64,qint64)),
- SLOT(dataTransferProgress(qint64,qint64)) );
-
- return nFtp;
-}
-
-void tst_QFtp::addCommand( QFtp::Command cmd, int id )
-{
- ids << id;
- CommandResult res;
- res.id = id;
- res.success = -1;
- resultMap[ cmd ] = res;
-}
-
-bool tst_QFtp::fileExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &file, const QString &cdDir )
-{
- init();
- ftp = newFtp();
- // ### make these tests work
- if (ftp->currentId() != 0) {
- qWarning("ftp->currentId() != 0");
- return false;
- }
-
- if (ftp->state() != QFtp::Unconnected) {
- qWarning("ftp->state() != QFtp::Unconnected");
- return false;
- }
-
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- if ( !cdDir.isNull() )
- addCommand( QFtp::Cd, ftp->cd( cdDir ) );
- addCommand( QFtp::List, ftp->list( file ) );
- addCommand( QFtp::Close, ftp->close() );
-
- inFileDirExistsFunction = true;
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() ) {
- // ### make this test work
- qWarning("tst_QFtp::fileExists: Network operation timed out");
- return false;
- }
- inFileDirExistsFunction = false;
-
- ResMapIt it = resultMap.find( QFtp::ConnectToHost );
- // ### make these tests work
- if (it == resultMap.end()) {
- qWarning("it != resultMap.end()");
- return false;
- }
-
- if (it.value().success == -1) {
- qWarning("it.value().success != -1");
- return false;
- }
-
- if ( it.value().success == 1 ) {
- for ( uint i=0; i < (uint) listInfo_i.count(); i++ ) {
- if ( QFileInfo(listInfo_i[i].name()).fileName() == QFileInfo(file).fileName() )
- return true;
- }
- }
-
- //this is not a good warning considering sometime this function is used to test that a file does not exist
- //qWarning("file doesn't exist");
- return false;
-}
-
-bool tst_QFtp::dirExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &cdDir, const QString &dirToCreate )
-{
- init();
- ftp = newFtp();
- // ### make these tests work
- // QCOMPARE( ftp->currentId(), 0 );
- // QCOMPARE( (int)ftp->state(), (int)QFtp::Unconnected );
-
- addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
- addCommand( QFtp::Login, ftp->login( user, password ) );
- if ( dirToCreate.startsWith( QLatin1Char('/') ) )
- addCommand( QFtp::Cd, ftp->cd( dirToCreate ) );
- else
- addCommand( QFtp::Cd, ftp->cd( cdDir + QLatin1Char('/') + dirToCreate ) );
- addCommand( QFtp::Close, ftp->close() );
-
- inFileDirExistsFunction = true;
- QTestEventLoop::instance().enterLoop( 30 );
- delete ftp;
- ftp = 0;
- if ( QTestEventLoop::instance().timeout() ) {
- // ### make this test work
- // QFAIL( msgTimedOut(host, port) );
- qWarning("tst_QFtp::dirExists: Network operation timed out");
- return false;
- }
- inFileDirExistsFunction = false;
-
- ResMapIt it = resultMap.find( QFtp::Cd );
- // ### make these tests work
- // QVERIFY( it != resultMap.end() );
- // QVERIFY( it.value().success != -1 );
- return it.value().success == 1;
-}
-
-void tst_QFtp::doneSignal()
-{
- QFtp ftp;
- QSignalSpy spy(&ftp, SIGNAL(done(bool)));
-
- ftp.connectToHost(QtNetworkSettings::ftpServerName());
- ftp.login("anonymous");
- ftp.list();
- ftp.close();
-
- done_success = 0;
- connect(&ftp, SIGNAL(done(bool)), &(QTestEventLoop::instance()), SLOT(exitLoop()));
- QTestEventLoop::instance().enterLoop(61);
- if (QTestEventLoop::instance().timeout())
- QFAIL("Network operation timed out");
-
- QCOMPARE(spy.count(), 1);
- QCOMPARE(spy.first().first().toBool(), false);
-}
-
-void tst_QFtp::queueMoreCommandsInDoneSlot()
-{
- QSKIP("Task 127050 && 113966");
-
- QFtp ftp;
- QSignalSpy doneSpy(&ftp, SIGNAL(done(bool)));
- QSignalSpy commandFinishedSpy(&ftp, SIGNAL(commandFinished(int,bool)));
-
- this->ftp = &ftp;
- connect(&ftp, SIGNAL(done(bool)), this, SLOT(cdUpSlot(bool)));
-
- ftp.connectToHost("ftp.qt-project.org");
- ftp.login();
- ftp.cd("qt");
- ftp.rmdir("qtest-removedir-noexist");
-
- while ( ftp.hasPendingCommands() || ftp.currentCommand() != QFtp::None ) {
- QCoreApplication::instance()->processEvents(QEventLoop::AllEvents
- | QEventLoop::WaitForMoreEvents);
- }
-
- QCOMPARE(doneSpy.count(), 2);
- QCOMPARE(doneSpy.first().first().toBool(), true);
- QCOMPARE(doneSpy.last().first().toBool(), false);
-
- QCOMPARE(commandFinishedSpy.count(), 6);
- int firstId = commandFinishedSpy.at(0).at(0).toInt();
- QCOMPARE(commandFinishedSpy.at(0).at(1).toBool(), false);
- QCOMPARE(commandFinishedSpy.at(1).at(0).toInt(), firstId + 1);
- QCOMPARE(commandFinishedSpy.at(1).at(1).toBool(), false);
- QCOMPARE(commandFinishedSpy.at(2).at(0).toInt(), firstId + 2);
- QCOMPARE(commandFinishedSpy.at(2).at(1).toBool(), false);
- QCOMPARE(commandFinishedSpy.at(3).at(0).toInt(), firstId + 3);
- QCOMPARE(commandFinishedSpy.at(3).at(1).toBool(), true);
- QCOMPARE(commandFinishedSpy.at(4).at(0).toInt(), firstId + 4);
- QCOMPARE(commandFinishedSpy.at(4).at(1).toBool(), false);
- QCOMPARE(commandFinishedSpy.at(5).at(0).toInt(), firstId + 5);
- QCOMPARE(commandFinishedSpy.at(5).at(1).toBool(), false);
-
- this->ftp = 0;
-}
-
-void tst_QFtp::cdUpSlot(bool error)
-{
- if (error) {
- ftp->cd("..");
- ftp->cd("qt");
- }
-}
-
-void tst_QFtp::qtbug7359Crash()
-{
- QFtp ftp;
- ftp.connectToHost("127.0.0.1");
-
- QElapsedTimer t;
- int elapsed;
-
- t.start();
- while ((elapsed = t.elapsed()) < 200)
- QCoreApplication::processEvents(QEventLoop::AllEvents, 200 - elapsed);
-
- ftp.close();
- t.restart();
- while ((elapsed = t.elapsed()) < 1000)
- QCoreApplication::processEvents(QEventLoop::AllEvents, 1000 - elapsed);
-
- ftp.connectToHost("127.0.0.1");
-
- t.restart();
- while ((elapsed = t.elapsed()) < 2000)
- QCoreApplication::processEvents(QEventLoop::AllEvents, 2000 - elapsed);
-}
-
-class FtpLocalServer : public QTcpServer
-{
- Q_OBJECT
-
-public:
- explicit FtpLocalServer(QObject *parent = 0) : QTcpServer(parent) {}
- virtual ~FtpLocalServer() { delete mSocket; }
- void startServer(qint16 port = 0);
- void stopServer();
-
- enum class ReplyCodes {
- ServiceReady = 220,
- ServiceClose = 221,
- NeedPassword = 331,
- LoginFailed = 530,
- RequestDeny = 550
- };
-
- void sendResponse(ReplyCodes code);
-
- inline QString getRawUser() { return rawUser; }
- inline QString getRawPassword() { return rawPass; }
-
-signals:
- void onStarted();
- void onStopped();
-
-public slots:
- void socketReadyRead();
- void socketDisconnected();
-
-protected:
- virtual void incomingConnection(qintptr handle);
-
-private:
- QTcpSocket *mSocket = nullptr;
- QString rawUser;
- QString rawPass;
-};
-
-void FtpLocalServer::startServer(qint16 port)
-{
- if (listen(QHostAddress::Any, port))
- emit onStarted(); // Notify connected objects
- else
- qDebug("Could not start FTP server");
-}
-
-void FtpLocalServer::stopServer()
-{
- close();
- emit onStopped(); // Notify connected objects
-}
-
-void FtpLocalServer::sendResponse(ReplyCodes code)
-{
- if (mSocket)
- {
- QString response;
- switch (code) {
- case ReplyCodes::ServiceReady:
- response = QString("220 Service ready for new user.\r\n");
- break;
- case ReplyCodes::ServiceClose:
- response = QString("221 Service closing control connection.\r\n");
- break;
- case ReplyCodes::NeedPassword:
- response = QString("331 User name okay, need password.\r\n");
- break;
- case ReplyCodes::LoginFailed:
- response = QString("530 Not logged in.\r\n");
- break;
- case ReplyCodes::RequestDeny:
- response = QString("550 Requested action not taken.\r\n");
- break;
- default:
- qDebug("Unimplemented response code: %u", static_cast<uint>(code));
- break;
- }
-
- if (!response.isEmpty())
- mSocket->write(response.toLatin1());
- }
-}
-
-void FtpLocalServer::incomingConnection(qintptr handle)
-{
- mSocket = new QTcpSocket(this);
- if (mSocket == nullptr || !mSocket->setSocketDescriptor(handle))
- {
- delete mSocket;
- mSocket = nullptr;
- qDebug() << handle << " Error binding socket";
- return;
- }
-
- connect(mSocket, SIGNAL(readyRead()), this, SLOT(socketReadyRead()));
- connect(mSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
-
- // Accept client connection
- sendResponse(ReplyCodes::ServiceReady);
-}
-
-void FtpLocalServer::socketReadyRead()
-{
- QString data;
- if (mSocket)
- data.append(mSocket->readAll());
-
- // RFC959 Upper and lower case alphabetic characters are to be treated identically.
- if (data.startsWith("USER", Qt::CaseInsensitive)) {
- rawUser = data;
- sendResponse(ReplyCodes::NeedPassword);
- } else if (data.startsWith("PASS", Qt::CaseInsensitive)) {
- rawPass = data;
- sendResponse(ReplyCodes::LoginFailed);
- } else {
- sendResponse(ReplyCodes::RequestDeny);
- }
-}
-
-void FtpLocalServer::socketDisconnected()
-{
- // Cleanup
- if (mSocket)
- mSocket->deleteLater();
- deleteLater();
-}
-
-void tst_QFtp::loginURL_data()
-{
- QTest::addColumn<QString>("user");
- QTest::addColumn<QString>("password");
- QTest::addColumn<QString>("rawUser");
- QTest::addColumn<QString>("rawPass");
-
- QTest::newRow("no username, no password")
- << QString() << QString()
- << QString("USER anonymous\r\n") << QString("PASS anonymous@\r\n");
-
- QTest::newRow("username, no password")
- << QString("someone") << QString()
- << QString("USER someone\r\n") << QString();
-
- QTest::newRow("username, empty password")
- << QString("someone") << QString("")
- << QString("USER someone\r\n") << QString("PASS \r\n");
-
- QTest::newRow("username, password")
- << QString("someone") << QString("nonsense")
- << QString("USER someone\r\n") << QString("PASS nonsense\r\n");
-
- QTest::newRow("anonymous, no password")
- << QString("anonymous") << QString()
- << QString("USER anonymous\r\n") << QString("PASS anonymous@\r\n");
-
- QTest::newRow("Anonymous, no password")
- << QString("Anonymous") << QString()
- << QString("USER Anonymous\r\n") << QString("PASS anonymous@\r\n");
-
- QTest::newRow("anonymous, empty password")
- << QString("anonymous") << QString("")
- << QString("USER anonymous\r\n") << QString("PASS \r\n");
-
- QTest::newRow("ANONYMOUS, password")
- << QString("ANONYMOUS") << QString("nonsense")
- << QString("USER ANONYMOUS\r\n") << QString("PASS nonsense\r\n");
-}
-
-void tst_QFtp::loginURL()
-{
- QFETCH_GLOBAL(bool, setProxy);
- if (setProxy)
- QSKIP("This test should be verified on the local machine without proxies");
-
- QFETCH(QString, user);
- QFETCH(QString, password);
- QFETCH(QString, rawUser);
- QFETCH(QString, rawPass);
-
- FtpLocalServer server;
- server.startServer();
- uint port = server.serverPort();
-
- ftp = newFtp();
- addCommand(QFtp::ConnectToHost,
- ftp->connectToHost("127.0.0.1", port));
- addCommand(QFtp::Login, ftp->login(user, password));
-
- QTestEventLoop::instance().enterLoop(5);
- delete ftp;
- ftp = nullptr;
- server.stopServer();
- if (QTestEventLoop::instance().timeout())
- QFAIL(msgTimedOut("127.0.0.1", port));
-
- QCOMPARE(server.getRawUser(), rawUser);
- QCOMPARE(server.getRawPassword(), rawPass);
-}
-
-QTEST_MAIN(tst_QFtp)
-
-#include "tst_qftp.moc"
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
index c8be0902ba..e470dd02b4 100644
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
@@ -208,11 +208,9 @@ private Q_SLOTS:
void getFromFile();
void getFromFileSpecial_data();
void getFromFileSpecial();
-#if QT_CONFIG(ftp)
void getFromFtp_data();
void getFromFtp();
void getFromFtpAfterError(); // QTBUG-40797
-#endif
void getFromHttp_data();
void getFromHttp();
void getErrors_data();
@@ -223,11 +221,9 @@ private Q_SLOTS:
#endif // !QT_NO_NETWORKPROXY
void putToFile_data();
void putToFile();
-#if QT_CONFIG(ftp)
void putToFtp_data();
void putToFtp();
void putToFtpWithInvalidCredentials(); // QTBUG-40622
-#endif
void putToHttp_data();
void putToHttp();
void putToHttpSynchronous_data();
@@ -268,11 +264,9 @@ private Q_SLOTS:
void ioGetFromFileSpecial();
void ioGetFromFile_data();
void ioGetFromFile();
-#if QT_CONFIG(ftp)
void ioGetFromFtp_data();
void ioGetFromFtp();
void ioGetFromFtpWithReuse();
-#endif
void ioGetFromHttp();
void ioGetFromBuiltinHttp_data();
@@ -314,10 +308,8 @@ private Q_SLOTS:
void ioPutToFileFromLocalSocket();
void ioPutToFileFromProcess_data();
void ioPutToFileFromProcess();
-#if QT_CONFIG(ftp)
void ioPutToFtpFromFile_data();
void ioPutToFtpFromFile();
-#endif
void ioPutToHttpFromFile_data();
void ioPutToHttpFromFile();
void ioPostToHttpFromFile_data();
@@ -464,10 +456,8 @@ private Q_SLOTS:
void closeDuringDownload_data();
void closeDuringDownload();
-#if QT_CONFIG(ftp)
void ftpAuthentication_data();
void ftpAuthentication();
-#endif
void emitErrorForAllReplies(); // QTBUG-36890
@@ -517,6 +507,8 @@ private:
QString testDataDir;
bool notEnoughDataForFastSender;
+
+ bool ftpSupported = false;
};
const QByteArray tst_QNetworkReply::httpEmpty200Response =
@@ -1320,6 +1312,8 @@ tst_QNetworkReply::tst_QNetworkReply()
#ifndef QT_NO_NETWORKPROXY
}
#endif // !QT_NO_NETWORKPROXY
+
+ ftpSupported = manager.supportedSchemes().contains("ftp");
}
tst_QNetworkReply::~tst_QNetworkReply()
@@ -1836,9 +1830,10 @@ void tst_QNetworkReply::getFromFileSpecial()
QCOMPARE(reply->readAll(), resource.readAll());
}
-#if QT_CONFIG(ftp)
void tst_QNetworkReply::getFromFtp_data()
{
+ if (!ftpSupported)
+ QSKIP("FTP is not supported");
QTest::addColumn<QString>("referenceName");
QTest::addColumn<QString>("url");
@@ -1872,6 +1867,9 @@ void tst_QNetworkReply::getFromFtp()
void tst_QNetworkReply::getFromFtpAfterError()
{
+ if (!ftpSupported)
+ QSKIP("FTP is not supported");
+
QNetworkRequest invalidRequest(QUrl("ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/invalid.txt"));
QNetworkReplyPtr invalidReply;
invalidReply.reset(manager.get(invalidRequest));
@@ -1889,7 +1887,6 @@ void tst_QNetworkReply::getFromFtpAfterError()
QCOMPARE(validReply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), reference.size());
QCOMPARE(validReply->readAll(), reference.readAll());
}
-#endif
void tst_QNetworkReply::getFromHttp_data()
{
@@ -2059,21 +2056,26 @@ void tst_QNetworkReply::getErrors_data()
QTest::newRow("file-permissions") << "file:" + filePermissionFileName
<< int(QNetworkReply::ContentAccessDenied) << 0 << true;
-#if QT_CONFIG(ftp)
- // ftp: errors
- QTest::newRow("ftp-host") << "ftp://invalid.test.qt-project.org/foo.txt"
- << int(QNetworkReply::HostNotFoundError) << 0 << true;
- QTest::newRow("ftp-no-path") << "ftp://" + QtNetworkSettings::ftpServerName()
- << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
- QTest::newRow("ftp-is-dir") << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest"
- << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
- QTest::newRow("ftp-dir-not-readable") << "ftp://" + QtNetworkSettings::ftpServerName() + "/pub/dir-not-readable/foo.txt"
- << int(QNetworkReply::ContentAccessDenied) << 0 << true;
- QTest::newRow("ftp-file-not-readable") << "ftp://" + QtNetworkSettings::ftpServerName() + "/pub/file-not-readable.txt"
- << int(QNetworkReply::ContentAccessDenied) << 0 << true;
- QTest::newRow("ftp-exist") << "ftp://" + QtNetworkSettings::ftpServerName() + "/pub/this-file-doesnt-exist.txt"
- << int(QNetworkReply::ContentNotFoundError) << 0 << true;
-#endif
+ if (ftpSupported) {
+ // ftp: errors
+ QTest::newRow("ftp-host") << "ftp://invalid.test.qt-project.org/foo.txt"
+ << int(QNetworkReply::HostNotFoundError) << 0 << true;
+ QTest::newRow("ftp-no-path")
+ << "ftp://" + QtNetworkSettings::ftpServerName()
+ << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
+ QTest::newRow("ftp-is-dir")
+ << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest"
+ << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true;
+ QTest::newRow("ftp-dir-not-readable")
+ << "ftp://" + QtNetworkSettings::ftpServerName() + "/pub/dir-not-readable/foo.txt"
+ << int(QNetworkReply::ContentAccessDenied) << 0 << true;
+ QTest::newRow("ftp-file-not-readable")
+ << "ftp://" + QtNetworkSettings::ftpServerName() + "/pub/file-not-readable.txt"
+ << int(QNetworkReply::ContentAccessDenied) << 0 << true;
+ QTest::newRow("ftp-exist")
+ << "ftp://" + QtNetworkSettings::ftpServerName() + "/pub/this-file-doesnt-exist.txt"
+ << int(QNetworkReply::ContentNotFoundError) << 0 << true;
+ }
// http: errors
QTest::newRow("http-host") << "http://invalid.test.qt-project.org/"
@@ -2127,11 +2129,9 @@ void tst_QNetworkReply::getErrors()
QVERIFY2(waitResult != Timeout, msgGetErrors(waitResult, reply));
QFETCH(int, error);
-#if QT_CONFIG(ftp)
QEXPECT_FAIL("ftp-is-dir", "QFtp cannot provide enough detail", Abort);
// the line below is not necessary
QEXPECT_FAIL("ftp-dir-not-readable", "QFtp cannot provide enough detail", Abort);
-#endif
QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
QTEST(reply->readAll().isEmpty(), "dataIsEmpty");
@@ -2201,9 +2201,10 @@ void tst_QNetworkReply::putToFile()
QCOMPARE(contents, data);
}
-#if QT_CONFIG(ftp)
void tst_QNetworkReply::putToFtp_data()
{
+ if (!ftpSupported)
+ QSKIP("FTP is not supported");
putToFile_data();
}
@@ -2255,6 +2256,8 @@ void tst_QNetworkReply::putToFtp()
void tst_QNetworkReply::putToFtpWithInvalidCredentials()
{
+ if (!ftpSupported)
+ QSKIP("FTP is not supported");
QUrl url("ftp://" + QtNetworkSettings::ftpServerName());
url.setPath(QString("/qtest/upload/qnetworkaccess-putToFtp-%1-%2")
.arg(QTest::currentDataTag())
@@ -2274,7 +2277,6 @@ void tst_QNetworkReply::putToFtpWithInvalidCredentials()
r->close();
}
}
-#endif
void tst_QNetworkReply::putToHttp_data()
{
@@ -3275,9 +3277,10 @@ void tst_QNetworkReply::ioGetFromFile()
QCOMPARE(reader.data, data);
}
-#if QT_CONFIG(ftp)
void tst_QNetworkReply::ioGetFromFtp_data()
{
+ if (!ftpSupported)
+ QSKIP("FTP is not supported");
QTest::addColumn<QString>("fileName");
QTest::addColumn<qint64>("expectedSize");
@@ -3312,6 +3315,8 @@ void tst_QNetworkReply::ioGetFromFtp()
void tst_QNetworkReply::ioGetFromFtpWithReuse()
{
+ if (!ftpSupported)
+ QSKIP("FTP is not supported");
QString fileName = testDataDir + "/rfc3252.txt";
QFile reference(fileName);
reference.open(QIODevice::ReadOnly);
@@ -3342,7 +3347,6 @@ void tst_QNetworkReply::ioGetFromFtpWithReuse()
QCOMPARE(reader1.data, referenceData);
QCOMPARE(reader2.data, referenceData);
}
-#endif
void tst_QNetworkReply::ioGetFromHttp()
{
@@ -4199,26 +4203,28 @@ void tst_QNetworkReply::ioGetWithManyProxies_data()
<< "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
<< QNetworkReply::NoError;
-#if QT_CONFIG(ftp)
- // FTP request with FTP caching proxy
- proxyList.clear();
- proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121);
- QTest::newRow("ftp-on-ftp")
- << proxyList << proxyList.at(0)
- << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt"
- << QNetworkReply::NoError;
-
- // The following test doesn't work because QFtp is too limited
- // It can only talk to its own kind of proxies
-
- // FTP request with SOCKSv5 transparent proxy
- proxyList.clear();
- proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081);
- QTest::newRow("ftp-on-socks")
- << proxyList << proxyList.at(0)
- << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt"
- << QNetworkReply::NoError;
-#endif
+ if (ftpSupported) {
+ // FTP request with FTP caching proxy
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy,
+ QtNetworkSettings::ftpProxyServerName(), 2121);
+ QTest::newRow("ftp-on-ftp")
+ << proxyList << proxyList.at(0)
+ << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt"
+ << QNetworkReply::NoError;
+
+ // The following test doesn't work because QFtp is too limited
+ // It can only talk to its own kind of proxies
+
+ // FTP request with SOCKSv5 transparent proxy
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::Socks5Proxy,
+ QtNetworkSettings::socksProxyServerName(), 1081);
+ QTest::newRow("ftp-on-socks")
+ << proxyList << proxyList.at(0)
+ << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt"
+ << QNetworkReply::NoError;
+ }
#ifndef QT_NO_SSL
// HTTPS with HTTP transparent proxy
@@ -4248,24 +4254,27 @@ void tst_QNetworkReply::ioGetWithManyProxies_data()
<< "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
<< QNetworkReply::ProxyNotFoundError;
-#if QT_CONFIG(ftp)
- // FTP request with HTTP caching proxy
- proxyList.clear();
- proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129);
- QTest::newRow("ftp-on-http")
- << proxyList << QNetworkProxy()
- << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt"
- << QNetworkReply::ProxyNotFoundError;
-
- // FTP request with HTTP caching proxies
- proxyList.clear();
- proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129)
- << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3130);
- QTest::newRow("ftp-on-multiple-http")
- << proxyList << QNetworkProxy()
- << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt"
- << QNetworkReply::ProxyNotFoundError;
-#endif
+ if (ftpSupported) {
+ // FTP request with HTTP caching proxy
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy,
+ QtNetworkSettings::httpProxyServerName(), 3129);
+ QTest::newRow("ftp-on-http")
+ << proxyList << QNetworkProxy()
+ << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt"
+ << QNetworkReply::ProxyNotFoundError;
+
+ // FTP request with HTTP caching proxies
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy,
+ QtNetworkSettings::httpProxyServerName(), 3129)
+ << QNetworkProxy(QNetworkProxy::HttpCachingProxy,
+ QtNetworkSettings::httpProxyServerName(), 3130);
+ QTest::newRow("ftp-on-multiple-http")
+ << proxyList << QNetworkProxy()
+ << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt"
+ << QNetworkReply::ProxyNotFoundError;
+ }
#ifndef QT_NO_SSL
// HTTPS with HTTP caching proxy
@@ -4333,16 +4342,18 @@ void tst_QNetworkReply::ioGetWithManyProxies_data()
<< "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"
<< QNetworkReply::NoError;
-#if QT_CONFIG(ftp)
- // FTP request with HTTP Caching + FTP
- proxyList.clear();
- proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129)
- << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121);
- QTest::newRow("ftp-on-http+ftp")
- << proxyList << proxyList.at(1) // second proxy should be used
- << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt"
- << QNetworkReply::NoError;
-#endif
+ if (ftpSupported) {
+ // FTP request with HTTP Caching + FTP
+ proxyList.clear();
+ proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy,
+ QtNetworkSettings::httpProxyServerName(), 3129)
+ << QNetworkProxy(QNetworkProxy::FtpCachingProxy,
+ QtNetworkSettings::ftpProxyServerName(), 2121);
+ QTest::newRow("ftp-on-http+ftp")
+ << proxyList << proxyList.at(1) // second proxy should be used
+ << "ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt"
+ << QNetworkReply::NoError;
+ }
#ifndef QT_NO_SSL
// HTTPS request with HTTP Caching + HTTP transparent
@@ -4403,9 +4414,7 @@ void tst_QNetworkReply::ioGetWithManyProxies()
#endif
QFETCH(QNetworkReply::NetworkError, expectedError);
-#if QT_CONFIG(ftp)
QEXPECT_FAIL("ftp-on-socks", "QFtp is too limited and won't accept non-FTP proxies", Abort);
-#endif
QCOMPARE(reply->error(), expectedError);
// Verify that the factory was called properly
@@ -4421,10 +4430,8 @@ void tst_QNetworkReply::ioGetWithManyProxies()
if (proxyUsed.type() == QNetworkProxy::NoProxy) {
QCOMPARE(authspy.count(), 0);
} else {
-#if QT_CONFIG(ftp)
if (QByteArray(QTest::currentDataTag()).startsWith("ftp-"))
return; // No authentication with current FTP or with FTP proxies
-#endif
QCOMPARE(authspy.count(), 1);
QCOMPARE(qvariant_cast<QNetworkProxy>(authspy.at(0).at(0)), proxyUsed);
}
@@ -4605,9 +4612,10 @@ void tst_QNetworkReply::ioPutToFileFromProcess()
#endif // QT_CONFIG(process)
}
-#if QT_CONFIG(ftp)
void tst_QNetworkReply::ioPutToFtpFromFile_data()
{
+ if (!ftpSupported)
+ QSKIP("FTP is not supported");
ioPutToFileFromFile_data();
}
@@ -4654,7 +4662,6 @@ void tst_QNetworkReply::ioPutToFtpFromFile()
QTestEventLoop::instance().enterLoop(10);
QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
}
-#endif
void tst_QNetworkReply::ioPutToHttpFromFile_data()
{
@@ -8032,9 +8039,10 @@ void tst_QNetworkReply::closeDuringDownload_data()
{
QTest::addColumn<QUrl>("url");
QTest::newRow("http") << QUrl("http://" + QtNetworkSettings::httpServerName() + "/bigfile");
-#if QT_CONFIG(ftp)
- QTest::newRow("ftp") << QUrl("ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/bigfile");
-#endif
+ if (ftpSupported) {
+ QTest::newRow("ftp") << QUrl("ftp://" + QtNetworkSettings::ftpServerName()
+ + "/qtest/bigfile");
+ }
}
void tst_QNetworkReply::closeDuringDownload()
@@ -8052,9 +8060,10 @@ void tst_QNetworkReply::closeDuringDownload()
QVERIFY(destroySpy.wait());
}
-#if QT_CONFIG(ftp)
void tst_QNetworkReply::ftpAuthentication_data()
{
+ if (!ftpSupported)
+ QSKIP("FTP is not supported");
QTest::addColumn<QString>("referenceName");
QTest::addColumn<QString>("url");
QTest::addColumn<int>("error");
@@ -8079,7 +8088,6 @@ void tst_QNetworkReply::ftpAuthentication()
QCOMPARE(reply->url(), request.url());
QCOMPARE(reply->error(), QNetworkReply::NetworkError(error));
}
-#endif
void tst_QNetworkReply::emitErrorForAllReplies() // QTBUG-36890
{
@@ -9056,9 +9064,8 @@ void tst_QNetworkReply::autoDeleteRepliesAttribute_data()
QTest::newRow("http") << QUrl("http://QInvalidDomain.qt/test");
QTest::newRow("https") << QUrl("https://QInvalidDomain.qt/test");
-#if QT_CONFIG(ftp)
- QTest::newRow("ftp") << QUrl("ftp://QInvalidDomain.qt/test");
-#endif
+ if (ftpSupported)
+ QTest::newRow("ftp") << QUrl("ftp://QInvalidDomain.qt/test");
QTest::newRow("file") << QUrl("file:///thisfolderdoesn'texist/probably.txt");
#ifdef Q_OS_WIN
// Only supported on windows.