cutelyst  4.9.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 
17 Q_LOGGING_CATEGORY(C_SERVER_SM, "cutelyst.server.staticmap", QtWarningMsg)
18 
19 using namespace Cutelyst;
20 using namespace Qt::Literals::StringLiterals;
21 
22 StaticMap::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 
34 void 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 
51 void 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 
68 bool 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 
87 bool 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"
Request request
Definition: context.h:72
QString & prepend(QChar ch)
qsizetype size() const const
Container for HTTP headers.
Definition: headers.h:23
void setLastModified(const QByteArray &value)
Definition: headers.cpp:272
QByteArrayList headers(QByteArrayView key) const
Definition: headers.cpp:419
bool exists() const const
Request req
Definition: context.h:67
The Cutelyst Context.
Definition: context.h:42
void setContentType(const QByteArray &contentType)
Definition: headers.cpp:77
Headers headers() const noexcept
Definition: request.cpp:313
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
void beforePrepareAction(Cutelyst::Context *c, bool *skipMethod)
virtual bool setup(Cutelyst::Application *app) override
Definition: staticmap.cpp:27
The Cutelyst namespace holds all public Cutelyst API.
QDateTime lastModified() const const
void push_back(QChar ch)
bool isValid() const const
QByteArray ifModifiedSince() const noexcept
Definition: headers.cpp:206
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString mid(qsizetype position, qsizetype n) const const
Base class for Cutelyst Plugins.
Definition: plugin.h:24
The Cutelyst application.
Definition: application.h:72
Response * response() const noexcept
Definition: context.cpp:98
void setHeader(const QByteArray &key, const QByteArray &value)
Definition: headers.cpp:437