Cutelyst  3.5.0
upload.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2014-2022 Daniel Nicoletti <dantti12@gmail.com>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 #include "upload_p.h"
6 #include "common.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  qint64 totalRead = 0;
54  while (!atEnd()) {
55  qint64 in = read(block, sizeof(block));
56  if (in <= 0)
57  break;
58  totalRead += in;
59  if (in != out.write(block, in)) {
60  setErrorString(QLatin1String("Failure to write block"));
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(QStringLiteral("Cannot create %1 for output").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 
86 {
87 #ifndef QT_NO_TEMPORARYFILE
88  Q_D(Upload);
89  QTemporaryFile *ret;
90  if (templateName.isEmpty()) {
91  ret = new QTemporaryFile(this);
92  } else {
93  ret = new QTemporaryFile(templateName, this);
94  }
95 
96  if (ret->open()) {
97  bool error = false;
98  qint64 posOrig = d->pos;
99  seek(0);
100 
101  char block[4096];
102  qint64 totalRead = 0;
103  while (!atEnd()) {
104  qint64 in = read(block, sizeof(block));
105  if (in <= 0)
106  break;
107  totalRead += in;
108  if (in != ret->write(block, in)) {
109  setErrorString(QLatin1String("Failure to write block"));
110  qCWarning(CUTELYST_UPLOAD) << errorString();
111  error = true;
112  break;
113  }
114  }
115 
116  if (error) {
117  ret->remove();
118  }
119  ret->seek(0);
120  seek(posOrig);
121 
122  return ret;
123  } else {
124  qCWarning(CUTELYST_UPLOAD) << "Failed to open temporary file.";
125  }
126  delete ret;
127 #else
128  Q_UNUSED(templateName)
129 #endif
130 
131  return nullptr;
132 }
133 
134 qint64 Upload::pos() const
135 {
136  Q_D(const Upload);
137  return d->pos;
138 }
139 
140 qint64 Upload::size() const
141 {
142  Q_D(const Upload);
143  return d->endOffset - d->startOffset;
144 }
145 
146 bool Upload::seek(qint64 pos)
147 {
148  Q_D(Upload);
149  if (pos <= size()) {
151  d->pos = pos;
152  return true;
153  }
154  return false;
155 }
156 
157 Upload::Upload(UploadPrivate *prv) :
158  d_ptr(prv)
159 {
160  Q_D(Upload);
161  open(prv->device->openMode());
162  const QString disposition = prv->headers.contentDisposition();
163  int start = disposition.indexOf(QLatin1String("name=\""));
164  if (start != -1) {
165  start += 6;
166  int end = disposition.indexOf(QLatin1Char('"'), start);
167  if (end != -1) {
168  d->name = disposition.mid(start, end - start);
169  }
170  }
171 
172  start = disposition.indexOf(QLatin1String("filename=\""));
173  if (start != -1) {
174  start += 10;
175  int end = disposition.indexOf(QLatin1Char('"'), start);
176  if (end != -1) {
177  d->filename = disposition.mid(start, end - start);
178  }
179  }
180 }
181 
182 Upload::~Upload()
183 {
184  delete d_ptr;
185 }
186 
188 {
189  Q_D(const Upload);
190  return d->name;
191 }
192 
193 qint64 Upload::readData(char *data, qint64 maxlen)
194 {
195  Q_D(Upload);
196  qint64 posOrig = d->device->pos();
197 
198  d->device->seek(d->startOffset + d->pos);
199  qint64 len = d->device->read(data,
200  qMin(size() - d->pos, maxlen));
201  d->device->seek(posOrig);
202  d->pos += len;
203  return len;
204 }
205 
206 qint64 Upload::readLineData(char *data, qint64 maxlen)
207 {
208  Q_D(Upload);
209  qint64 posOrig = d->device->pos();
210 
211  d->device->seek(d->startOffset + d->pos);
212  qint64 len = d->device->readLine(data,
213  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"
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
virtual bool atEnd() const const
virtual bool seek(qint64 pos)
virtual qint64 readLineData(char *data, qint64 maxlen) override
Definition: upload.cpp:206
bool remove()
QString errorString() const const
virtual qint64 writeData(const char *data, qint64 maxSize) override
Definition: upload.cpp:219
virtual bool open(QIODevice::OpenMode mode)
QString contentType() const
Definition: upload.cpp:21
Cutelyst Upload handles file upload request
Definition: upload.h:22
bool isEmpty() const const
qint64 read(char *data, qint64 maxSize)
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
virtual bool seek(qint64 pos) override
Definition: upload.cpp:146
Headers headers() const
Definition: upload.cpp:27
virtual void close() override
virtual bool seek(qint64 pos) override
QString filename() const
Definition: upload.cpp:15
bool save(const QString &filename)
Definition: upload.cpp:33
qint64 write(const char *data, qint64 maxSize)
void setErrorString(const QString &str)
Upload(UploadPrivate *prv)
Definition: upload.cpp:157
virtual qint64 pos() const override
Definition: upload.cpp:134
virtual qint64 readData(char *data, qint64 maxlen) override
Definition: upload.cpp:193
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QTemporaryFile * createTemporaryFile(const QString &templateName=QString())
Definition: upload.cpp:85
virtual qint64 size() const override
Definition: upload.cpp:140
QString name() const
Definition: upload.cpp:187