KIO

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

KDE's Doxygen guidelines are available online.