cutelyst  4.4.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
upload.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2014-2022 Daniel Nicoletti <dantti12@gmail.com>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 #include "common.h"
6 #include "upload_p.h"
7 
8 #include <QDir>
9 #include <QFile>
10 #include <QFileInfo>
11 #include <QTemporaryFile>
12 
13 using namespace Cutelyst;
14 
16 {
17  Q_D(const Upload);
18  return d->filename;
19 }
20 
22 {
23  Q_D(const Upload);
24  return d->headers.contentType();
25 }
26 
28 {
29  Q_D(const Upload);
30  return d->headers;
31 }
32 
33 bool Upload::save(const QString &newName)
34 {
35  Q_D(Upload);
36 
37  bool error = false;
38  QString fileTemplate = QStringLiteral("%1/qt_temp.XXXXXX");
39  QFile out(fileTemplate.arg(QFileInfo(newName).path()));
40  if (!out.open(QIODevice::ReadWrite)) {
41  error = true;
42  }
43 
44  if (error) {
45  out.close();
46  setErrorString(QLatin1String("Failed to open file for saving: ") + out.errorString());
47  qCWarning(CUTELYST_UPLOAD) << errorString();
48  } else {
49  qint64 posOrig = d->pos;
50  seek(0);
51 
52  char block[4096];
53  while (!atEnd()) {
54  qint64 in = read(block, sizeof(block));
55  if (in <= 0)
56  break;
57  if (in != out.write(block, in)) {
58  setErrorString(QLatin1String("Failure to write block"));
59  qCWarning(CUTELYST_UPLOAD) << errorString();
60  error = true;
61  break;
62  }
63  }
64 
65  if (error) {
66  out.remove();
67  }
68 
69  if (!error && !out.rename(newName)) {
70  error = true;
71  setErrorString(QStringLiteral("Cannot create %1 for output").arg(newName));
72  qCWarning(CUTELYST_UPLOAD) << errorString();
73  }
74  if (error) {
75  out.remove();
76  }
77  seek(posOrig);
78  }
79 
80  return !error;
81 }
82 
83 std::unique_ptr<QTemporaryFile> Upload::createTemporaryFile(const QString &templateName)
84 {
85  std::unique_ptr<QTemporaryFile> ret;
86 
87 #ifndef QT_NO_TEMPORARYFILE
88  Q_D(Upload);
89  if (templateName.isEmpty()) {
90  ret = std::make_unique<QTemporaryFile>();
91  } else {
92  ret = std::make_unique<QTemporaryFile>(templateName);
93  }
94 
95  if (ret->open()) {
96  bool error = false;
97  qint64 posOrig = d->pos;
98  seek(0);
99 
100  char block[4096];
101  while (!atEnd()) {
102  qint64 in = read(block, sizeof(block));
103  if (in <= 0)
104  break;
105 
106  if (in != ret->write(block, in)) {
107  setErrorString(QLatin1String("Failure to write block"));
108  qCWarning(CUTELYST_UPLOAD) << errorString();
109  error = true;
110  break;
111  }
112  }
113 
114  if (error) {
115  ret->remove();
116  }
117  ret->seek(0);
118  seek(posOrig);
119 
120  return ret;
121  } else {
122  qCWarning(CUTELYST_UPLOAD) << "Failed to open temporary file.";
123  }
124  ret.reset();
125 #else
126  Q_UNUSED(templateName);
127 #endif
128 
129  return ret;
130 }
131 
132 qint64 Upload::pos() const
133 {
134  Q_D(const Upload);
135  return d->pos;
136 }
137 
138 qint64 Upload::size() const
139 {
140  Q_D(const Upload);
141  return d->endOffset - d->startOffset;
142 }
143 
144 bool Upload::seek(qint64 pos)
145 {
146  Q_D(Upload);
147  if (pos <= size()) {
149  d->pos = pos;
150  return true;
151  }
152  return false;
153 }
154 
155 Upload::Upload(UploadPrivate *prv)
156  : d_ptr(prv)
157 {
158  Q_D(Upload);
159  open(prv->device->openMode());
160  const QByteArray disposition = prv->headers.contentDisposition();
161  int start = disposition.indexOf("name=\"");
162  if (start != -1) {
163  start += 6;
164  int end = disposition.indexOf(u'"', start);
165  if (end != -1) {
166  // TODO
167  d->name = QString::fromLatin1(disposition.sliced(start, end - start));
168  }
169  }
170 
171  start = disposition.indexOf("filename=\"");
172  if (start != -1) {
173  start += 10;
174  int end = disposition.indexOf('"', start);
175  if (end != -1) {
176  d->filename = QString::fromLatin1(disposition.sliced(start, end - start));
177  }
178  }
179 }
180 
182 {
183  delete d_ptr;
184 }
185 
187 {
188  Q_D(const Upload);
189  return d->name;
190 }
191 
192 qint64 Upload::readData(char *data, qint64 maxlen)
193 {
194  Q_D(Upload);
195  qint64 posOrig = d->device->pos();
196 
197  d->device->seek(d->startOffset + d->pos);
198  qint64 len = d->device->read(data, qMin(size() - d->pos, maxlen));
199  d->device->seek(posOrig);
200  d->pos += len;
201  return len;
202 }
203 
204 qint64 Upload::readLineData(char *data, qint64 maxlen)
205 {
206  Q_D(Upload);
207  qint64 posOrig = d->device->pos();
208 
209  d->device->seek(d->startOffset + d->pos);
210  qint64 len = d->device->readLine(data, qMin(size() - d->pos, maxlen));
211  d->device->seek(posOrig);
212  d->pos += len;
213  return len;
214 }
215 
216 qint64 Upload::writeData(const char *data, qint64 maxSize)
217 {
218  Q_UNUSED(data);
219  Q_UNUSED(maxSize);
220  return -1;
221 }
222 
223 #include "moc_upload.cpp"
Container for HTTP headers.
Definition: headers.h:24
Cutelyst Upload handles file upload requests.
Definition: upload.h:26
Upload(UploadPrivate *prv)
Definition: upload.cpp:155
bool seek(qint64 pos) override
Definition: upload.cpp:144
qint64 pos() const override
Definition: upload.cpp:132
qint64 readLineData(char *data, qint64 maxlen) override
Definition: upload.cpp:204
QString filename() const
Definition: upload.cpp:15
qint64 writeData(const char *data, qint64 maxSize) override
Definition: upload.cpp:216
QByteArray contentType() const
Definition: upload.cpp:21
virtual ~Upload() override
Definition: upload.cpp:181
QString name() const
Definition: upload.cpp:186
Headers headers() const
Definition: upload.cpp:27
qint64 readData(char *data, qint64 maxlen) override
Definition: upload.cpp:192
qint64 size() const override
Definition: upload.cpp:138
std::unique_ptr< QTemporaryFile > createTemporaryFile(const QString &templateName={})
Definition: upload.cpp:83
bool save(const QString &filename)
Definition: upload.cpp:33
The Cutelyst namespace holds all public Cutelyst API.
qsizetype indexOf(QByteArrayView bv, qsizetype from) const const
QByteArray sliced(qsizetype pos) const const
bool open(FILE *fh, QIODeviceBase::OpenMode mode, QFileDevice::FileHandleFlags handleFlags)
bool remove()
bool rename(const QString &newName)
virtual void close() override
virtual bool atEnd() const const
QString errorString() const const
virtual bool open(QIODeviceBase::OpenMode mode)
QByteArray read(qint64 maxSize)
virtual bool seek(qint64 pos)
void setErrorString(const QString &str)
qint64 write(const QByteArray &data)
QString arg(Args &&... args) const const
QString fromLatin1(QByteArrayView str)
bool isEmpty() const const