cutelyst 4.3.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 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
83std::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
132qint64 Upload::pos() const
133{
134 Q_D(const Upload);
135 return d->pos;
136}
137
138qint64 Upload::size() const
139{
140 Q_D(const Upload);
141 return d->endOffset - d->startOffset;
142}
143
144bool 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
155Upload::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
192qint64 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
204qint64 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
216qint64 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