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