cutelyst 5.0.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
13using namespace Cutelyst;
14using 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
34bool 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
85std::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
135qint64 Upload::pos() const
136{
137 Q_D(const Upload);
138 return d->pos;
139}
140
141qint64 Upload::size() const
142{
143 Q_D(const Upload);
144 return d->endOffset - d->startOffset;
145}
146
147bool Upload::seek(qint64 pos)
148{
149 Q_D(Upload);
150 if (pos <= size()) {
152 d->pos = pos;
153 return true;
154 }
155 return false;
156}
157
158Upload::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
195qint64 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
207qint64 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
219qint64 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"
Container for HTTP headers.
Definition headers.h:24
Cutelyst Upload handles file upload requests.
Definition upload.h:26
Upload(UploadPrivate *prv)
Definition upload.cpp:158
bool seek(qint64 pos) override
Definition upload.cpp:147
qint64 pos() const override
Definition upload.cpp:135
qint64 readLineData(char *data, qint64 maxlen) override
Definition upload.cpp:207
QString filename() const
Definition upload.cpp:16
qint64 writeData(const char *data, qint64 maxSize) override
Definition upload.cpp:219
QByteArray contentType() const
Definition upload.cpp:22
virtual ~Upload() override
Definition upload.cpp:184
QString name() const
Definition upload.cpp:189
Headers headers() const
Definition upload.cpp:28
qint64 readData(char *data, qint64 maxlen) override
Definition upload.cpp:195
qint64 size() const override
Definition upload.cpp:141
std::unique_ptr< QTemporaryFile > createTemporaryFile(const QString &templateName={})
Definition upload.cpp:85
bool save(const QString &filename)
Definition upload.cpp:34
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