Qt 4.8
qnetworkaccessftpbackend.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
44 #include "QtNetwork/qauthenticator.h"
45 #include "private/qnoncontiguousbytedevice_p.h"
46 
47 #ifndef QT_NO_FTP
48 
50 
51 enum {
53 };
54 
55 static QByteArray makeCacheKey(const QUrl &url)
56 {
57  QUrl copy = url;
58  copy.setPort(url.port(DefaultFtpPort));
59  return "ftp-connection:" +
62 }
63 
66  const QNetworkRequest &request) const
67 {
68  // is it an operation we know of?
69  switch (op) {
72  break;
73 
74  default:
75  // no, we can't handle this operation
76  return 0;
77  }
78 
79  QUrl url = request.url();
80  if (url.scheme().compare(QLatin1String("ftp"), Qt::CaseInsensitive) == 0)
81  return new QNetworkAccessFtpBackend;
82  return 0;
83 }
84 
86 {
87  // Q_OBJECT
88 public:
90  {
91  setExpires(true);
92  setShareable(false);
93  }
94 
95  void dispose()
96  {
97  connect(this, SIGNAL(done(bool)), this, SLOT(deleteLater()));
98  close();
99  }
100 };
101 
103  : ftp(0), uploadDevice(0), totalBytes(0), helpId(-1), sizeId(-1), mdtmId(-1),
104  supportsSize(false), supportsMdtm(false), state(Idle)
105 {
106 }
107 
109 {
110  //if backend destroyed while in use, then abort (this is the code path from QNetworkReply::abort)
111  if (ftp && state != Disconnecting)
112  ftp->abort();
114 }
115 
117 {
118 #ifndef QT_NO_NETWORKPROXY
119  QNetworkProxy proxy;
120  foreach (const QNetworkProxy &p, proxyList()) {
121  // use the first FTP proxy
122  // or no proxy at all
124  || p.type() == QNetworkProxy::NoProxy) {
125  proxy = p;
126  break;
127  }
128  }
129 
130  // did we find an FTP proxy or a NoProxy?
131  if (proxy.type() == QNetworkProxy::DefaultProxy) {
132  // unsuitable proxies
134  tr("No suitable proxy found"));
135  finished();
136  return;
137  }
138 
139 #endif
140 
141  QUrl url = this->url();
142  if (url.path().isEmpty()) {
143  url.setPath(QLatin1String("/"));
144  setUrl(url);
145  }
146  if (url.path().endsWith(QLatin1Char('/'))) {
148  tr("Cannot open %1: is a directory").arg(url.toString()));
149  finished();
150  return;
151  }
152  state = LoggingIn;
153 
155  QByteArray cacheKey = makeCacheKey(url);
156  if (!objectCache->requestEntry(cacheKey, this,
159 #ifndef QT_NO_BEARERMANAGEMENT
160  //copy network session down to the QFtp
161  ftp->setProperty("_q_networksession", property("_q_networksession"));
162 #endif
163 #ifndef QT_NO_NETWORKPROXY
164  if (proxy.type() == QNetworkProxy::FtpCachingProxy)
165  ftp->setProxy(proxy.hostName(), proxy.port());
166 #endif
167  ftp->connectToHost(url.host(), url.port(DefaultFtpPort));
168  ftp->login(url.userName(), url.password());
169 
170  objectCache->addEntry(cacheKey, ftp);
172  }
173 
174  // Put operation
177  uploadDevice->setParent(this);
178  }
179 }
180 
182 {
185  ftp->abort();
186 }
187 
189 {
190  if (state == Transferring && ftp && ftp->bytesAvailable())
191  ftpReadyRead();
192 }
193 
195 {
196  ftp = static_cast<QNetworkAccessCachedFtpConnection *>(o);
197  connect(ftp, SIGNAL(done(bool)), SLOT(ftpDone()));
198  connect(ftp, SIGNAL(rawCommandReply(int,QString)), SLOT(ftpRawCommandReply(int,QString)));
199  connect(ftp, SIGNAL(readyRead()), SLOT(ftpReadyRead()));
200 
201  // is the login process done already?
202  if (ftp->state() == QFtp::LoggedIn)
203  ftpDone();
204 
205  // no, defer the actual operation until after we've logged in
206 }
207 
209 {
211 
212  if (ftp) {
213  disconnect(ftp, 0, this, 0);
214 
217 
218  ftp = 0;
219  }
220 }
221 
223 {
224  // the last command we sent is done
225  if (state == LoggingIn && ftp->state() != QFtp::LoggedIn) {
226  if (ftp->state() == QFtp::Connected) {
227  // the login did not succeed
228  QUrl newUrl = url();
229  newUrl.setUserInfo(QString());
230  setUrl(newUrl);
231 
232  QAuthenticator auth;
233  authenticationRequired(&auth);
234 
235  if (!auth.isNull()) {
236  // try again:
237  newUrl.setUserName(auth.user());
238  ftp->login(auth.user(), auth.password());
239  return;
240  }
241 
243  tr("Logging in to %1 failed: authentication required")
244  .arg(url().host()));
245  } else {
246  // we did not connect
248  switch (ftp->error()) {
249  case QFtp::HostNotFound:
251  break;
252 
255  break;
256 
257  default:
259  break;
260  }
261 
262  error(code, ftp->errorString());
263  }
264 
265  // we're not connected, so remove the cache entry:
268 
269  disconnect(ftp, 0, this, 0);
270  ftp->dispose();
271  ftp = 0;
272 
274  finished();
275  return;
276  }
277 
278  // check for errors:
279  if (ftp->error() != QFtp::NoError) {
280  QString msg;
282  msg = tr("Error while downloading %1: %2");
283  else
284  msg = tr("Error while uploading %1: %2");
285  msg = msg.arg(url().toString(), ftp->errorString());
286 
287  if (state == Statting)
288  // file probably doesn't exist
290  else
292 
294  finished();
295  }
296 
297  if (state == LoggingIn) {
300  // send help command to find out if server supports "SIZE" and "MDTM"
301  QString command = url().path();
302  command.prepend(QLatin1String("%1 "));
303  helpId = ftp->rawCommand(QLatin1String("HELP")); // get supported commands
304  } else {
305  ftpDone();
306  }
307  } else if (state == CheckingFeatures) {
308  state = Statting;
310  // logged in successfully, send the stat requests (if supported)
311  QString command = url().path();
312  command.prepend(QLatin1String("%1 "));
313  if (supportsSize) {
314  ftp->rawCommand(QLatin1String("TYPE I"));
315  sizeId = ftp->rawCommand(command.arg(QLatin1String("SIZE"))); // get size
316  }
317  if (supportsMdtm)
318  mdtmId = ftp->rawCommand(command.arg(QLatin1String("MDTM"))); // get modified time
319  if (!supportsSize && !supportsMdtm)
320  ftpDone(); // no commands sent, move to the next state
321  } else {
322  ftpDone();
323  }
324  } else if (state == Statting) {
325  // statted successfully, send the actual request
328 
331  setCachingEnabled(true);
332  ftp->get(url().path(), 0, type);
333  } else {
334  ftp->put(uploadDevice, url().path(), type);
335  }
336 
337  } else if (state == Transferring) {
338  // upload or download finished
340  finished();
341  }
342 }
343 
345 {
346  QByteArray data = ftp->readAll();
347  QByteDataBuffer list;
348  list.append(data);
349  data.clear(); // important because of implicit sharing!
350  writeDownstreamData(list);
351 }
352 
354 {
355  //qDebug() << "FTP reply:" << code << text;
356  int id = ftp->currentId();
357 
358  if ((id == helpId) && ((code == 200) || (code == 214))) { // supported commands
359  // the "FEAT" ftp command would be nice here, but it is not part of the
360  // initial FTP RFC 959, neither ar "SIZE" nor "MDTM" (they are all specified
361  // in RFC 3659)
362  if (text.contains(QLatin1String("SIZE"), Qt::CaseSensitive))
363  supportsSize = true;
364  if (text.contains(QLatin1String("MDTM"), Qt::CaseSensitive))
365  supportsMdtm = true;
366  } else if (code == 213) { // file status
367  if (id == sizeId) {
368  // reply to the size command
370 #ifndef QT_NO_DATESTRING
371  } else if (id == mdtmId) {
372  QDateTime dt = QDateTime::fromString(text, QLatin1String("yyyyMMddHHmmss"));
374 #endif
375  }
376  }
377 }
378 
380 
381 #endif // QT_NO_FTP
QNetworkProxy::ProxyType type() const
Returns the proxy type for this instance.
QBool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.h:904
void ftpRawCommandReply(int code, const QString &text)
void setUserInfo(const QString &userInfo)
Sets the user info of the URL to userInfo.
Definition: qurl.cpp:4615
qlonglong toLongLong(bool *ok=0, int base=10) const
Returns the string converted to a long long using base base, which is 10 by default and must be betwe...
Definition: qstring.cpp:5943
int type
Definition: qmetatype.cpp:239
int connectToHost(const QString &host, quint16 port=21)
Connects to the FTP server host using port port.
Definition: qftp.cpp:1763
bool requestEntry(const QByteArray &key, QObject *target, const char *member)
QByteArray readAll()
Reads all the bytes available from the data socket and returns them.
Definition: qftp.cpp:2154
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
static QByteArray makeCacheKey(const QUrl &url)
QPointer< QNetworkAccessCachedFtpConnection > ftp
QString toString(FormattingOptions options=None) const
Returns the human-displayable string representation of the URL.
Definition: qurl.cpp:5896
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
QString & prepend(QChar c)
Definition: qstring.h:261
#define SLOT(a)
Definition: qobjectdefs.h:226
int rawCommand(const QString &command)
Sends the raw FTP command command to the FTP server.
Definition: qftp.cpp:2115
bool setProperty(const char *name, const QVariant &value)
Sets the value of the object&#39;s name property to value.
Definition: qobject.cpp:3755
NetworkError
Indicates all possible error conditions found during the processing of the request.
Definition: qnetworkreply.h:70
Operation
Indicates the operation this reply is processing.
void setPath(const QString &path)
Sets the path of the URL to path.
Definition: qurl.cpp:4960
static QString tr(const char *sourceText, const char *comment=0, int n=-1)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
void append(QByteDataBuffer &other)
Definition: qbytedata_p.h:77
The QUrl class provides a convenient interface for working with URLs.
Definition: qurl.h:61
The QString class provides a Unicode character string.
Definition: qstring.h:83
int put(const QByteArray &data, const QString &file, TransferType type=Binary)
Writes a copy of the given data to the file called file on the server.
Definition: qftp.cpp:1977
QString host() const
Returns the host of the URL if it is defined; otherwise an empty string is returned.
Definition: qurl.cpp:4837
The QFtp class provides an implementation of the client side of FTP protocol.
Definition: qftp.h:59
void abort()
Aborts the current command and deletes all scheduled commands.
Definition: qftp.cpp:2188
QString path() const
Returns the path of the URL.
Definition: qurl.cpp:4977
QUrl url() const
Returns the URL this network request is referring to.
int currentId() const
Returns the identifier of the FTP command that is being executed or 0 if there is no command being ex...
Definition: qftp.cpp:2203
void setParent(QObject *)
Makes the object a child of parent.
Definition: qobject.cpp:1950
int port() const
Returns the port of the URL, or -1 if the port is unspecified.
Definition: qurl.cpp:4916
#define SIGNAL(a)
Definition: qobjectdefs.h:227
The QNetworkProxy class provides a network layer proxy.
static QString toString(Register *reg, int type, bool *ok=0)
static QDateTime fromString(const QString &s, Qt::DateFormat f=Qt::TextDate)
Returns the QDateTime represented by the string, using the format given, or an invalid datetime if th...
Definition: qdatetime.cpp:3487
QNonContiguousByteDevice * createUploadByteDevice()
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
void addEntry(const QByteArray &key, CacheableObject *entry)
int get(const QString &file, QIODevice *dev=0, TransferType type=Binary)
Downloads the file file from the server.
Definition: qftp.cpp:1937
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
static QNetworkAccessCache * getObjectCache(QNetworkAccessBackend *backend)
#define emit
Definition: qobjectdefs.h:76
QList< QNetworkProxy > proxyList() const
static const char * data(const QByteArray &arr)
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
QNetworkAccessManager::Operation operation() const
The QAuthenticator class provides an authentication object.
void ftpConnectionReady(QNetworkAccessCache::CacheableObject *object)
QByteArray toEncoded(FormattingOptions options=None) const
Returns the encoded representation of the URL if it&#39;s valid; otherwise an empty QByteArray is returne...
Definition: qurl.cpp:5949
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
Disconnects signal in object sender from method in object receiver.
Definition: qobject.cpp:2895
QString userName() const
Returns the user name of the URL if it is defined; otherwise an empty string is returned.
Definition: qurl.cpp:4667
QString scheme() const
Returns the scheme of the URL.
Definition: qurl.cpp:4550
void authenticationRequired(QAuthenticator *auth)
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
void error(QNetworkReply::NetworkError code, const QString &errorString)
int compare(const QString &s) const
Definition: qstring.cpp:5037
The QDateTime class provides date and time functions.
Definition: qdatetime.h:216
void setPort(int port)
Sets the port of the URL to port.
Definition: qurl.cpp:4897
void setUrl(const QUrl &url)
bool isNull() const
Returns true if the authenticator is null.
QString user() const
returns the user used for authentication.
int key
quint16 port() const
Returns the port of the proxy host.
QString errorString() const
Returns a human-readable description of the last error that occurred.
Definition: qftp.cpp:2305
qint64 bytesAvailable() const
Returns the number of bytes that can be read from the data socket at the moment.
Definition: qftp.cpp:2127
void writeDownstreamData(QByteDataBuffer &list)
static QIODevice * wrap(QNonContiguousByteDevice *byteDevice)
Wrap the byteDevice (possibly again) into a QIODevice.
TransferType
This enum identifies the data transfer type used with get and put commands.
Definition: qftp.h:103
The QNetworkRequest class holds a request to be sent with QNetworkAccessManager.
QVariant property(const char *name) const
Returns the value of the object&#39;s name property.
Definition: qobject.cpp:3807
void setCachingEnabled(bool enable)
void releaseEntry(const QByteArray &key)
int login(const QString &user=QString(), const QString &password=QString())
Logs in to the FTP server with the username user and the password password.
Definition: qftp.cpp:1791
QString password() const
returns the password used for authentication.
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition: qstring.cpp:3796
Error error() const
Returns the last error that occurred.
Definition: qftp.cpp:2289
int setProxy(const QString &host, quint16 port)
Enables use of the FTP proxy on host host and port port.
Definition: qftp.cpp:1842
void setUserName(const QString &userName)
Sets the URL&#39;s user name to userName.
Definition: qurl.cpp:4648
void removeEntry(const QByteArray &key)
QString password() const
Returns the password of the URL if it is defined; otherwise an empty string is returned.
Definition: qurl.cpp:4754
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
virtual QNetworkAccessBackend * create(QNetworkAccessManager::Operation op, const QNetworkRequest &request) const
State state() const
Returns the current state of the object.
Definition: qftp.cpp:2277
void clear()
Clears the contents of the byte array and makes it empty.
#define text
Definition: qobjectdefs.h:80
QString hostName() const
Returns the host name of the proxy host.