KIO

storedtransferjob.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 2000 Stephan Kulow <[email protected]>
3  2000-2009 David Faure <[email protected]>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include "storedtransferjob.h"
22 #include "job_p.h"
23 #include <KConfig>
24 #include <KConfigGroup>
25 #include <kurlauthorized.h>
26 #include <QTimer>
27 
28 using namespace KIO;
29 
30 class KIO::StoredTransferJobPrivate: public TransferJobPrivate
31 {
32 public:
33  StoredTransferJobPrivate(const QUrl &url, int command,
34  const QByteArray &packedArgs,
35  const QByteArray &_staticData)
36  : TransferJobPrivate(url, command, packedArgs, _staticData),
37  m_uploadOffset(0)
38  {}
39  StoredTransferJobPrivate(const QUrl &url, int command,
40  const QByteArray &packedArgs,
41  QIODevice *ioDevice)
42  : TransferJobPrivate(url, command, packedArgs, ioDevice),
43  m_uploadOffset(0)
44  {}
45 
46  QByteArray m_data;
47  int m_uploadOffset;
48 
49  void slotStoredData(KIO::Job *job, const QByteArray &data);
50  void slotStoredDataReq(KIO::Job *job, QByteArray &data);
51 
52  Q_DECLARE_PUBLIC(StoredTransferJob)
53 
54  static inline StoredTransferJob *newJob(const QUrl &url, int command,
55  const QByteArray &packedArgs,
56  const QByteArray &staticData, JobFlags flags)
57  {
59  *new StoredTransferJobPrivate(url, command, packedArgs, staticData));
61  if (!(flags & HideProgressInfo)) {
63  }
64  if (!(flags & NoPrivilegeExecution)) {
65  job->d_func()->m_privilegeExecutionEnabled = true;
66  job->d_func()->m_operationType = Transfer;
67  }
68  return job;
69  }
70 
71  static inline StoredTransferJob *newJob(const QUrl &url, int command,
72  const QByteArray &packedArgs,
73  QIODevice *ioDevice, JobFlags flags)
74  {
76  *new StoredTransferJobPrivate(url, command, packedArgs, ioDevice));
78  if (!(flags & HideProgressInfo)) {
80  }
81  if (!(flags & NoPrivilegeExecution)) {
82  job->d_func()->m_privilegeExecutionEnabled = true;
83  job->d_func()->m_operationType = Transfer;
84  }
85  return job;
86  }
87 };
88 
89 StoredTransferJob::StoredTransferJob(StoredTransferJobPrivate &dd)
90  : TransferJob(dd)
91 {
92  connect(this, SIGNAL(data(KIO::Job*,QByteArray)),
93  SLOT(slotStoredData(KIO::Job*,QByteArray)));
94  connect(this, SIGNAL(dataReq(KIO::Job*,QByteArray&)),
95  SLOT(slotStoredDataReq(KIO::Job*,QByteArray&)));
96 }
97 
98 StoredTransferJob::~StoredTransferJob()
99 {
100 }
101 
103 {
104  Q_D(StoredTransferJob);
105  Q_ASSERT(d->m_data.isNull()); // check that we're only called once
106  Q_ASSERT(d->m_uploadOffset == 0); // no upload started yet
107  d->m_data = arr;
108  setTotalSize(d->m_data.size());
109 }
110 
112 {
113  return d_func()->m_data;
114 }
115 
116 void StoredTransferJobPrivate::slotStoredData(KIO::Job *, const QByteArray &data)
117 {
118  // check for end-of-data marker:
119  if (data.size() == 0) {
120  return;
121  }
122  unsigned int oldSize = m_data.size();
123  m_data.resize(oldSize + data.size());
124  memcpy(m_data.data() + oldSize, data.data(), data.size());
125 }
126 
127 void StoredTransferJobPrivate::slotStoredDataReq(KIO::Job *, QByteArray &data)
128 {
129  // Inspired from kmail's KMKernel::byteArrayToRemoteFile
130  // send the data in 64 KB chunks
131  const int MAX_CHUNK_SIZE = 64 * 1024;
132  int remainingBytes = m_data.size() - m_uploadOffset;
133  if (remainingBytes > MAX_CHUNK_SIZE) {
134  // send MAX_CHUNK_SIZE bytes to the receiver (deep copy)
135  data = QByteArray(m_data.data() + m_uploadOffset, MAX_CHUNK_SIZE);
136  m_uploadOffset += MAX_CHUNK_SIZE;
137  //qDebug() << "Sending " << MAX_CHUNK_SIZE << " bytes ("
138  // << remainingBytes - MAX_CHUNK_SIZE << " bytes remain)\n";
139  } else {
140  // send the remaining bytes to the receiver (deep copy)
141  data = QByteArray(m_data.data() + m_uploadOffset, remainingBytes);
142  m_data = QByteArray();
143  m_uploadOffset = 0;
144  //qDebug() << "Sending " << remainingBytes << " bytes\n";
145  }
146 }
147 
148 StoredTransferJob *KIO::storedGet(const QUrl &url, LoadType reload, JobFlags flags)
149 {
150  // Send decoded path and encoded query
151  KIO_ARGS << url;
152  StoredTransferJob *job = StoredTransferJobPrivate::newJob(url, CMD_GET, packedArgs, QByteArray(), flags);
153  if (reload == Reload) {
154  job->addMetaData(QStringLiteral("cache"), QStringLiteral("reload"));
155  }
156  return job;
157 }
158 
159 StoredTransferJob *KIO::storedPut(const QByteArray &arr, const QUrl &url, int permissions,
160  JobFlags flags)
161 {
162  KIO_ARGS << url << qint8((flags & Overwrite) ? 1 : 0) << qint8((flags & Resume) ? 1 : 0) << permissions;
163  StoredTransferJob *job = StoredTransferJobPrivate::newJob(url, CMD_PUT, packedArgs, QByteArray(), flags);
164  job->setData(arr);
165  return job;
166 }
167 
168 StoredTransferJob *KIO::storedPut(QIODevice* input, const QUrl &url, int permissions,
169  JobFlags flags)
170 {
171  Q_ASSERT(input && input->isReadable());
172  KIO_ARGS << url << qint8((flags & Overwrite) ? 1 : 0) << qint8((flags & Resume) ? 1 : 0) << permissions;
173  StoredTransferJob *job = StoredTransferJobPrivate::newJob(url, CMD_PUT, packedArgs, input, flags);
174  if (!input->isSequential()) {
175  job->setTotalSize(input->size());
176  }
177  return job;
178 }
179 
180 namespace KIO
181 {
182 class PostErrorJob : public StoredTransferJob
183 {
184  Q_OBJECT
185 public:
186 
187  PostErrorJob(int _error, const QString &url, const QByteArray &packedArgs, const QByteArray &postData)
188  : StoredTransferJob(*new StoredTransferJobPrivate(QUrl(), CMD_SPECIAL, packedArgs, postData))
189  {
190  setError(_error);
191  setErrorText(url);
192  }
193 
194  PostErrorJob(int _error, const QString &url, const QByteArray &packedArgs, QIODevice *ioDevice)
195  : StoredTransferJob(*new StoredTransferJobPrivate(QUrl(), CMD_SPECIAL, packedArgs, ioDevice))
196  {
197  setError(_error);
198  setErrorText(url);
199  }
200 };
201 }
202 
203 static int isUrlPortBad(const QUrl &url)
204 {
205  int _error = 0;
206 
207  // filter out some malicious ports
208  static const int bad_ports[] = {
209  1, // tcpmux
210  7, // echo
211  9, // discard
212  11, // systat
213  13, // daytime
214  15, // netstat
215  17, // qotd
216  19, // chargen
217  20, // ftp-data
218  21, // ftp-cntl
219  22, // ssh
220  23, // telnet
221  25, // smtp
222  37, // time
223  42, // name
224  43, // nicname
225  53, // domain
226  77, // priv-rjs
227  79, // finger
228  87, // ttylink
229  95, // supdup
230  101, // hostriame
231  102, // iso-tsap
232  103, // gppitnp
233  104, // acr-nema
234  109, // pop2
235  110, // pop3
236  111, // sunrpc
237  113, // auth
238  115, // sftp
239  117, // uucp-path
240  119, // nntp
241  123, // NTP
242  135, // loc-srv / epmap
243  139, // netbios
244  143, // imap2
245  179, // BGP
246  389, // ldap
247  512, // print / exec
248  513, // login
249  514, // shell
250  515, // printer
251  526, // tempo
252  530, // courier
253  531, // Chat
254  532, // netnews
255  540, // uucp
256  556, // remotefs
257  587, // sendmail
258  601, //
259  989, // ftps data
260  990, // ftps
261  992, // telnets
262  993, // imap/SSL
263  995, // pop3/SSL
264  1080, // SOCKS
265  2049, // nfs
266  4045, // lockd
267  6000, // x11
268  6667, // irc
269  0
270  };
271  if (url.port() != 80) {
272  const int port = url.port();
273  for (int cnt = 0; bad_ports[cnt] && bad_ports[cnt] <= port; ++cnt)
274  if (port == bad_ports[cnt]) {
275  _error = KIO::ERR_POST_DENIED;
276  break;
277  }
278  }
279 
280  if (_error) {
281  static bool override_loaded = false;
282  static QList< int > *overriden_ports = nullptr;
283  if (!override_loaded) {
284  KConfig cfg(QStringLiteral("kio_httprc"));
285  overriden_ports = new QList< int >;
286  *overriden_ports = cfg.group(QString()).readEntry("OverriddenPorts", QList<int>());
287  override_loaded = true;
288  }
289  for (QList< int >::ConstIterator it = overriden_ports->constBegin();
290  it != overriden_ports->constEnd();
291  ++it) {
292  if (overriden_ports->contains(url.port())) {
293  _error = 0;
294  }
295  }
296  }
297 
298  // filter out non https? protocols
299  if ((url.scheme() != QLatin1String("http")) && (url.scheme() != QLatin1String("https"))) {
300  _error = KIO::ERR_POST_DENIED;
301  }
302 
303  if (!_error && !KUrlAuthorized::authorizeUrlAction(QStringLiteral("open"), QUrl(), url)) {
304  _error = KIO::ERR_ACCESS_DENIED;
305  }
306 
307  return _error;
308 }
309 
310 static KIO::PostErrorJob *precheckHttpPost(const QUrl &url, QIODevice *ioDevice, JobFlags flags)
311 {
312  // if request is not valid, return an invalid transfer job
313  const int _error = isUrlPortBad(url);
314 
315  if (_error) {
316  KIO_ARGS << (int)1 << url;
317  PostErrorJob *job = new PostErrorJob(_error, url.toString(), packedArgs, ioDevice);
319  if (!(flags & HideProgressInfo)) {
321  }
322  return job;
323  }
324 
325  // all is ok, return 0
326  return nullptr;
327 }
328 
329 static KIO::PostErrorJob *precheckHttpPost(const QUrl &url, const QByteArray &postData, JobFlags flags)
330 {
331  // if request is not valid, return an invalid transfer job
332  const int _error = isUrlPortBad(url);
333 
334  if (_error) {
335  KIO_ARGS << (int)1 << url;
336  PostErrorJob *job = new PostErrorJob(_error, url.toString(), packedArgs, postData);
338  if (!(flags & HideProgressInfo)) {
340  }
341  return job;
342  }
343 
344  // all is ok, return 0
345  return nullptr;
346 }
347 
348 TransferJob *KIO::http_post(const QUrl &url, const QByteArray &postData, JobFlags flags)
349 {
350  bool redirection = false;
351  QUrl _url(url);
352  if (_url.path().isEmpty()) {
353  redirection = true;
354  _url.setPath(QStringLiteral("/"));
355  }
356 
357  TransferJob *job = precheckHttpPost(_url, postData, flags);
358  if (job) {
359  return job;
360  }
361 
362  // Send http post command (1), decoded path and encoded query
363  KIO_ARGS << (int)1 << _url << static_cast<qint64>(postData.size());
364  job = TransferJobPrivate::newJob(_url, CMD_SPECIAL, packedArgs, postData, flags);
365 
366  if (redirection) {
367  QTimer::singleShot(0, job, SLOT(slotPostRedirection()));
368  }
369 
370  return job;
371 }
372 
373 TransferJob *KIO::http_post(const QUrl &url, QIODevice *ioDevice, qint64 size, JobFlags flags)
374 {
375  bool redirection = false;
376  QUrl _url(url);
377  if (_url.path().isEmpty()) {
378  redirection = true;
379  _url.setPath(QStringLiteral("/"));
380  }
381 
382  TransferJob *job = precheckHttpPost(_url, ioDevice, flags);
383  if (job) {
384  return job;
385  }
386 
387  // If no size is specified and the QIODevice is not a sequential one,
388  // attempt to obtain the size information from it.
389  Q_ASSERT(ioDevice);
390  if (size < 0) {
391  size = ((ioDevice && !ioDevice->isSequential()) ? ioDevice->size() : -1);
392  }
393 
394  // Send http post command (1), decoded path and encoded query
395  KIO_ARGS << (int)1 << _url << size;
396  job = TransferJobPrivate::newJob(_url, CMD_SPECIAL, packedArgs, ioDevice, flags);
397 
398  if (redirection) {
399  QTimer::singleShot(0, job, SLOT(slotPostRedirection()));
400  }
401 
402  return job;
403 }
404 
406 {
407  // Send decoded path and encoded query
408  KIO_ARGS << url;
409  TransferJob *job = TransferJobPrivate::newJob(url, CMD_DEL, packedArgs,
410  QByteArray(), flags);
411  return job;
412 }
413 
414 StoredTransferJob *KIO::storedHttpPost(const QByteArray &postData, const QUrl &url, JobFlags flags)
415 {
416  QUrl _url(url);
417  if (_url.path().isEmpty()) {
418  _url.setPath(QStringLiteral("/"));
419  }
420 
421  StoredTransferJob *job = precheckHttpPost(_url, postData, flags);
422  if (job) {
423  return job;
424  }
425 
426  // Send http post command (1), decoded path and encoded query
427  KIO_ARGS << (int)1 << _url << static_cast<qint64>(postData.size());
428  job = StoredTransferJobPrivate::newJob(_url, CMD_SPECIAL, packedArgs, postData, flags);
429  return job;
430 }
431 
432 StoredTransferJob *KIO::storedHttpPost(QIODevice *ioDevice, const QUrl &url, qint64 size, JobFlags flags)
433 {
434  QUrl _url(url);
435  if (_url.path().isEmpty()) {
436  _url.setPath(QStringLiteral("/"));
437  }
438 
439  StoredTransferJob *job = precheckHttpPost(_url, ioDevice, flags);
440  if (job) {
441  return job;
442  }
443 
444  // If no size is specified and the QIODevice is not a sequential one,
445  // attempt to obtain the size information from it.
446  Q_ASSERT(ioDevice);
447  if (size < 0) {
448  size = ((ioDevice && !ioDevice->isSequential()) ? ioDevice->size() : -1);
449  }
450 
451  // Send http post command (1), decoded path and encoded query
452  KIO_ARGS << (int)1 << _url << size;
453  job = StoredTransferJobPrivate::newJob(_url, CMD_SPECIAL, packedArgs, ioDevice, flags);
454  return job;
455 }
456 
457 // http post got redirected from http://host to http://host/ by TransferJob
458 // We must do this redirection ourselves because redirections by the
459 // slave change post jobs into get jobs.
460 void TransferJobPrivate::slotPostRedirection()
461 {
462  Q_Q(TransferJob);
463  //qDebug() << m_url;
464  // Tell the user about the new url.
465  emit q->redirection(q, m_url);
466 }
467 
468 TransferJob *KIO::put(const QUrl &url, int permissions, JobFlags flags)
469 {
470  KIO_ARGS << url << qint8((flags & Overwrite) ? 1 : 0) << qint8((flags & Resume) ? 1 : 0) << permissions;
471  return TransferJobPrivate::newJob(url, CMD_PUT, packedArgs, QByteArray(), flags);
472 }
473 
474 #include "moc_storedtransferjob.cpp"
475 #include "storedtransferjob.moc"
When set, automatically overwrite the destination if it exists already.
Definition: job_base.h:303
void addMetaData(const QString &key, const QString &value)
Add key/value pair to the meta data that is sent to the slave.
Definition: job.cpp:243
void setUiDelegate(KJobUiDelegate *delegate)
const QUrl & url() const
Returns the SimpleJob&#39;s URL.
Definition: simplejob.cpp:82
A namespace for KIO globals.
Definition: authinfo.h:34
KIOCORE_EXPORT StoredTransferJob * storedHttpPost(const QByteArray &arr, const QUrl &url, JobFlags flags=DefaultFlags)
HTTP POST (means: write) data from a single QByteArray.
Hide progress information dialog, i.e.
Definition: job_base.h:287
StoredTransferJob is a TransferJob (for downloading or uploading data) that also stores a QByteArray ...
void setError(int errorCode)
KConfigGroup group(const QByteArray &group)
int port(int defaultPort) const const
void setData(const QByteArray &arr)
Set data to be uploaded.
bool isReadable() const const
QString toString(QUrl::FormattingOptions options) const const
void setTotalSize(KIO::filesize_t bytes)
Set the total size of data that we are going to send in a put job.
Definition: transferjob.cpp:66
virtual bool isSequential() const const
QByteArray data() const
Get hold of the downloaded data.
void resize(int size)
void setPath(const QString &path, QUrl::ParsingMode mode)
void setErrorText(const QString &errorText)
When set, notifies the slave that application/job does not want privilege execution.
Definition: job_base.h:312
virtual qint64 size() const const
Q_OBJECTQ_OBJECT
When set, automatically append to the destination file if it exists already.
Definition: job_base.h:296
KIOCORE_EXPORT StoredTransferJob * storedPut(QIODevice *input, const QUrl &url, int permissions, JobFlags flags=DefaultFlags)
Put (means: write) data from a QIODevice.
bool isEmpty() const const
KIOCORE_EXPORT KJobUiDelegate * createDefaultJobUiDelegate()
Convenience method: use default factory, if there&#39;s one, to create a delegate and return it...
QString path(QUrl::ComponentFormattingOptions options) const const
KIOCORE_EXPORT StoredTransferJob * storedGet(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
Get (means: read), into a single QByteArray.
KIOCORE_EXPORT KJobTrackerInterface * getJobTracker()
Returns the job tracker to be used by all KIO jobs (in which HideProgressInfo is not set) ...
Definition: jobtracker.cpp:25
KIOCORE_EXPORT TransferJob * http_delete(const QUrl &url, JobFlags flags=DefaultFlags)
HTTP DELETE.
KIOCORE_EXPORT TransferJob * put(const QUrl &url, int permissions, JobFlags flags=DefaultFlags)
Put (means: write)
QString scheme() const const
void redirection(KIO::Job *job, const QUrl &url)
Signals a redirection.
bool contains(const T &value) const const
The base class for all jobs.
Definition: job_base.h:57
char * data()
Issued when trying to POST data to a certain Ports.
Definition: global.h:273
KIOCORE_EXPORT TransferJob * http_post(const QUrl &url, const QByteArray &postData, JobFlags flags=DefaultFlags)
HTTP POST (for form data).
virtual void registerJob(KJob *job)
QList::const_iterator constEnd() const const
The transfer job pumps data into and/or out of a Slave.
Definition: transferjob.h:38
QList::const_iterator constBegin() const const
int size() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
T readEntry(const QString &key, const T &aDefault) const
bool authorizeUrlAction(const QString &action, const QUrl &baseURL, const QUrl &destURL)
Returns whether a certain URL related action is authorized.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat Jul 11 2020 23:00:28 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.