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;
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
33bool 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 }
58 if (in != out.write(block, in)) {
59 setErrorString(QLatin1String("Failure to write block"));
60 qCWarning(CUTELYST_UPLOAD) << errorString();
61 error = true;
62 break;
63 }
64 }
65
66 if (error) {
67 out.remove();
68 }
69
70 if (!error && !out.rename(newName)) {
71 error = true;
72 setErrorString(QStringLiteral("Cannot create %1 for output").arg(newName));
73 qCWarning(CUTELYST_UPLOAD) << errorString();
74 }
75 if (error) {
76 out.remove();
77 }
78 seek(posOrig);
79 }
80
81 return !error;
82}
83
84std::unique_ptr<QTemporaryFile> Upload::createTemporaryFile(const QString &templateName)
85{
86 std::unique_ptr<QTemporaryFile> ret;
87
88#ifndef QT_NO_TEMPORARYFILE
89 Q_D(Upload);
90 if (templateName.isEmpty()) {
91 ret = std::make_unique<QTemporaryFile>();
92 } else {
93 ret = std::make_unique<QTemporaryFile>(templateName);
94 }
95
96 if (ret->open()) {
97 bool error = false;
98 qint64 posOrig = d->pos;
99 seek(0);
100
101 char block[4096];
102 while (!atEnd()) {
103 qint64 in = read(block, sizeof(block));
104 if (in <= 0) {
105 break;
106 }
107
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 ret.reset();
127#else
128 Q_UNUSED(templateName);
129#endif
130
131 return ret;
132}
133
134qint64 Upload::pos() const
135{
136 Q_D(const Upload);
137 return d->pos;
138}
139
140qint64 Upload::size() const
141{
142 Q_D(const Upload);
143 return d->endOffset - d->startOffset;
144}
145
146bool 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
157Upload::Upload(UploadPrivate *prv)
158 : d_ptr(prv)
159{
160 Q_D(Upload);
161 open(prv->device->openMode());
162 const QByteArray disposition = prv->headers.contentDisposition();
163 int start = disposition.indexOf("name=\"");
164 if (start != -1) {
165 start += 6;
166 int end = disposition.indexOf(u'"', start);
167 if (end != -1) {
168 // TODO
169 d->name = QString::fromLatin1(disposition.sliced(start, end - start));
170 }
171 }
172
173 start = disposition.indexOf("filename=\"");
174 if (start != -1) {
175 start += 10;
176 int end = disposition.indexOf('"', start);
177 if (end != -1) {
178 d->filename = QString::fromLatin1(disposition.sliced(start, end - start));
179 }
180 }
181}
182
184{
185 delete d_ptr;
186}
187
189{
190 Q_D(const Upload);
191 return d->name;
192}
193
194qint64 Upload::readData(char *data, qint64 maxlen)
195{
196 Q_D(Upload);
197 qint64 posOrig = d->device->pos();
198
199 d->device->seek(d->startOffset + d->pos);
200 qint64 len = d->device->read(data, qMin(size() - d->pos, maxlen));
201 d->device->seek(posOrig);
202 d->pos += len;
203 return len;
204}
205
206qint64 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, qMin(size() - d->pos, maxlen));
213 d->device->seek(posOrig);
214 d->pos += len;
215 return len;
216}
217
218qint64 Upload::writeData(const char *data, qint64 maxSize)
219{
220 Q_UNUSED(data);
221 Q_UNUSED(maxSize);
222 return -1;
223}
224
225#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:157
bool seek(qint64 pos) override
Definition upload.cpp:146
qint64 pos() const override
Definition upload.cpp:134
qint64 readLineData(char *data, qint64 maxlen) override
Definition upload.cpp:206
QString filename() const
Definition upload.cpp:15
qint64 writeData(const char *data, qint64 maxSize) override
Definition upload.cpp:218
QByteArray contentType() const
Definition upload.cpp:21
virtual ~Upload() override
Definition upload.cpp:183
QString name() const
Definition upload.cpp:188
Headers headers() const
Definition upload.cpp:27
qint64 readData(char *data, qint64 maxlen) override
Definition upload.cpp:194
qint64 size() const override
Definition upload.cpp:140
std::unique_ptr< QTemporaryFile > createTemporaryFile(const QString &templateName={})
Definition upload.cpp:84
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