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>
This commit is contained in:
parent
a1211c69d5
commit
4629a6b238
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user