summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRyan Chu <ryan.chu@qt.io>2017-12-22 14:53:13 +0100
committerRyan Chu <ryan.chu@qt.io>2018-02-19 08:31:26 +0000
commit4629a6b23883086eace25f87b33cd8f64952a392 (patch)
treea47060cdb2f58fcf3359f4ae8fa818b49ca1d674 /src
parenta1211c69d5aa9e4d60faed63edc737d41002d4fb (diff)
ftp backend: Dynamically resolving resource path with URL prefix
The code used to retrieve FTP resource with the path of QUrl as an absolute URL starting from the root directory. It is not always working with a relative URL because the root directory and working directory may be different. Depending on the implementation of FTP server, the reference directory of a relative URL could be either the root directory or the working directory. To resolve it, a new state “ResolvingPath” is added to resolve resource paths before retrieving. For both GET and PUT operations supported by QNetworkAccessFtpBackendFactory, the resource will be retrieved via its URL path. Depending on the prefix of the URL path, the path of working directory is prepended to the resource path as an absolute path starting with the working directory. If a URL path starts with “//” or “/%2F” user-input prefix, the resource will be retrieved by an absolute path starting with the root directory. If a path starts with /~/ or the working directory prefix, its resource will be retrieved from the working directory. Task-number: QTBUG-25034 Change-Id: I26198af1c0077f51565afd3f96050235c661f063 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/network/access/qnetworkaccessftpbackend.cpp61
-rw-r--r--src/network/access/qnetworkaccessftpbackend_p.h5
2 files changed, 60 insertions, 6 deletions
diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp
index c5404e4221..269845ed39 100644
--- a/src/network/access/qnetworkaccessftpbackend.cpp
+++ b/src/network/access/qnetworkaccessftpbackend.cpp
@@ -102,8 +102,8 @@ public:
};
QNetworkAccessFtpBackend::QNetworkAccessFtpBackend()
- : ftp(0), uploadDevice(0), totalBytes(0), helpId(-1), sizeId(-1), mdtmId(-1),
- supportsSize(false), supportsMdtm(false), state(Idle)
+ : ftp(0), uploadDevice(0), totalBytes(0), helpId(-1), sizeId(-1), mdtmId(-1), pwdId(-1),
+ supportsSize(false), supportsMdtm(false), supportsPwd(false), state(Idle)
{
}
@@ -302,13 +302,38 @@ void QNetworkAccessFtpBackend::ftpDone()
if (state == LoggingIn) {
state = CheckingFeatures;
- if (operation() == QNetworkAccessManager::GetOperation) {
- // send help command to find out if server supports "SIZE" and "MDTM"
+ // 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)
@@ -366,6 +391,34 @@ void QNetworkAccessFtpBackend::ftpRawCommandReply(int code, const QString &text)
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
diff --git a/src/network/access/qnetworkaccessftpbackend_p.h b/src/network/access/qnetworkaccessftpbackend_p.h
index 4bd082fb67..0b3d35dcd3 100644
--- a/src/network/access/qnetworkaccessftpbackend_p.h
+++ b/src/network/access/qnetworkaccessftpbackend_p.h
@@ -76,6 +76,7 @@ public:
//Connecting,
LoggingIn,
CheckingFeatures,
+ ResolvingPath,
Statting,
Transferring,
Disconnecting
@@ -107,8 +108,8 @@ private:
QPointer<QNetworkAccessCachedFtpConnection> ftp;
QIODevice *uploadDevice;
qint64 totalBytes;
- int helpId, sizeId, mdtmId;
- bool supportsSize, supportsMdtm;
+ int helpId, sizeId, mdtmId, pwdId;
+ bool supportsSize, supportsMdtm, supportsPwd;
State state;
};