cutelyst 4.8.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
staticmap.cpp
1/*
2 * SPDX-FileCopyrightText: (C) 2016-2023 Daniel Nicoletti <dantti12@gmail.com>
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5#include "staticmap.h"
6
7#include "socket.h"
8
9#include <Cutelyst/Application>
10#include <Cutelyst/Request>
11#include <Cutelyst/Response>
12
13#include <QDir>
14#include <QFile>
15#include <QLoggingCategory>
16
17Q_LOGGING_CATEGORY(C_SERVER_SM, "cutelyst.server.staticmap", QtWarningMsg)
18
19using namespace Cutelyst;
20using namespace Qt::Literals::StringLiterals;
21
22StaticMap::StaticMap(Cutelyst::Application *parent)
23 : Plugin(parent)
24{
25}
26
28{
29 connect(
30 app, &Cutelyst::Application::beforePrepareAction, this, &StaticMap::beforePrepareAction);
31 return true;
32}
33
34void StaticMap::addStaticMap(const QString &mountPoint, const QString &path, bool append)
35{
36 QString mp = mountPoint;
37 if (!mp.startsWith(u'/')) {
38 mp.prepend(u'/');
39 }
40
41 qCInfo(C_SERVER_SM) << "added mapping for" << mp << "=>" << path;
42
43 m_staticMaps.push_back({mp, path, append});
44 std::sort(m_staticMaps.begin(),
45 m_staticMaps.end(),
46 [](const MountPoint &a, const MountPoint &b) -> bool {
47 return a.mountPoint.size() < b.mountPoint.size();
48 });
49}
50
51void StaticMap::beforePrepareAction(Cutelyst::Context *c, bool *skipMethod)
52{
53 if (*skipMethod) {
54 return;
55 }
56
57 const QString path = c->req()->path();
58 for (const MountPoint &mp : m_staticMaps) {
59 if (path.startsWith(mp.mountPoint)) {
60 if (tryToServeFile(c, mp, path)) {
61 *skipMethod = true;
62 break;
63 }
64 }
65 }
66}
67
68bool StaticMap::tryToServeFile(Cutelyst::Context *c, const MountPoint &mp, const QString &path)
69{
70 QString localPath = path;
71 if (!mp.append) {
72 localPath = path.mid(mp.mountPoint.size());
73 }
74 while (localPath.startsWith(u'/')) {
75 localPath.remove(0, 1);
76 }
77
78 QDir dir(mp.path);
79 QString absFilePath = dir.absoluteFilePath(localPath);
80 if (!QFile::exists(absFilePath)) {
81 return false;
82 }
83
84 return serveFile(c, absFilePath);
85}
86
87bool StaticMap::serveFile(Cutelyst::Context *c, const QString &filename)
88{
89 auto res = c->response();
90 const QDateTime currentDateTime = QFileInfo(filename).lastModified();
91 if (!c->request()->headers().ifModifiedSince(currentDateTime)) {
92 res->setStatus(Response::NotModified);
93 return true;
94 }
95
96 auto file = new QFile(filename);
97 if (file->open(QFile::ReadOnly)) {
98 qCDebug(C_SERVER_SM) << "Serving" << filename;
99 Headers &headers = res->headers();
100
101 // set our open file
102 res->setBody(file);
103
104 // use the extension to match to be faster
105 QMimeType mimeType = m_db.mimeTypeForFile(filename, QMimeDatabase::MatchExtension);
106 if (mimeType.isValid()) {
107 headers.setContentType(mimeType.name().toLatin1());
108 }
109
110 headers.setLastModified(currentDateTime);
111 // Tell Firefox & friends its OK to cache, even over SSL
112 headers.setHeader("Cache-Control"_ba, "public"_ba);
113
114 return true;
115 }
116
117 qCWarning(C_SERVER_SM) << "Could not serve" << filename << file->errorString();
118 delete file;
119 return false;
120}
121
122#include "moc_staticmap.cpp"
The Cutelyst application.
Definition application.h:66
void beforePrepareAction(Cutelyst::Context *c, bool *skipMethod)
The Cutelyst Context.
Definition context.h:42
Request * request
Definition context.h:71
Request * req
Definition context.h:66
Response * response() const noexcept
Definition context.cpp:98
QByteArray ifModifiedSince() const noexcept
Definition headers.cpp:206
void setLastModified(const QByteArray &value)
Definition headers.cpp:272
void setContentType(const QByteArray &contentType)
Definition headers.cpp:77
void setHeader(const QByteArray &key, const QByteArray &value)
Definition headers.cpp:437
Base class for Cutelyst Plugins.
Definition plugin.h:25
Headers headers() const noexcept
Definition request.cpp:313
virtual bool setup(Cutelyst::Application *app) override
Definition staticmap.cpp:27
The Cutelyst namespace holds all public Cutelyst API.
bool exists() const const
bool isValid() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString mid(qsizetype position, qsizetype n) &&
QString & prepend(QChar ch)
void push_back(QChar ch)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
qsizetype size() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const