cutelyst  3.9.1
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
engine.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2013-2022 Daniel Nicoletti <dantti12@gmail.com>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 #include "application.h"
6 #include "common.h"
7 #include "context_p.h"
8 #include "engine_p.h"
9 #include "request_p.h"
10 #include "response_p.h"
11 
12 #include <QByteArray>
13 #include <QDir>
14 #include <QJsonDocument>
15 #include <QSettings>
16 #include <QThread>
17 #include <QUrl>
18 
19 using namespace Cutelyst;
20 
41 Engine::Engine(Cutelyst::Application *app, int workerCore, const QVariantMap &opts)
42  : d_ptr(new EnginePrivate)
43 {
44  Q_D(Engine);
45 
46  connect(
48 
49  d->opts = opts;
50  d->workerCore = workerCore;
51  d->app = app;
52 }
53 
54 Engine::~Engine()
55 {
56  delete d_ptr;
57 }
58 
64 {
65  Q_D(const Engine);
66  Q_ASSERT(d->app);
67  return d->app;
68 }
69 
89 int Engine::workerCore() const
90 {
91  Q_D(const Engine);
92  return d->workerCore;
93 }
94 
96 {
97  Q_D(Engine);
98 
99  if (thread() != QThread::currentThread()) {
100  qCCritical(CUTELYST_ENGINE) << "Cannot init application on a different thread";
101  return false;
102  }
103 
104  if (!d->app->setup(this)) {
105  qCCritical(CUTELYST_ENGINE) << "Failed to setup application";
106  return false;
107  }
108 
109  return true;
110 }
111 
113 {
114  Q_D(Engine);
115 
116  if (!d->app) {
117  qCCritical(CUTELYST_ENGINE) << "Failed to postForkApplication on a null application";
118  return false;
119  }
120 
122 
123  return d->app->enginePostFork();
124 }
125 
126 quint64 Engine::time()
127 {
128  return quint64(QDateTime::currentMSecsSinceEpoch() * 1000);
129 }
130 
131 const char *Engine::httpStatusMessage(quint16 status, int *len)
132 {
133  const char *ret;
134  switch (status) {
135  case Response::OK:
136  ret = "HTTP/1.1 200 OK";
137  break;
138  case Response::Found:
139  ret = "HTTP/1.1 302 Found";
140  break;
141  case Response::NotFound:
142  ret = "HTTP/1.1 404 Not Found";
143  break;
144  case Response::InternalServerError:
145  ret = "HTTP/1.1 500 Internal Server Error";
146  break;
147  case Response::MovedPermanently:
148  ret = "HTTP/1.1 301 Moved Permanently";
149  break;
150  case Response::NotModified:
151  ret = "HTTP/1.1 304 Not Modified";
152  break;
153  case Response::SeeOther:
154  ret = "HTTP/1.1 303 See Other";
155  break;
156  case Response::Forbidden:
157  ret = "HTTP/1.1 403 Forbidden";
158  break;
159  case Response::TemporaryRedirect:
160  ret = "HTTP/1.1 307 Temporary Redirect";
161  break;
162  case Response::Unauthorized:
163  ret = "HTTP/1.1 401 Unauthorized";
164  break;
165  case Response::BadRequest:
166  ret = "HTTP/1.1 400 Bad Request";
167  break;
168  case Response::MethodNotAllowed:
169  ret = "HTTP/1.1 405 Method Not Allowed";
170  break;
171  case Response::RequestTimeout:
172  ret = "HTTP/1.1 408 Request Timeout";
173  break;
174  case Response::Continue:
175  ret = "HTTP/1.1 100 Continue";
176  break;
177  case Response::SwitchingProtocols:
178  ret = "HTTP/1.1 101 Switching Protocols";
179  break;
180  case Response::Created:
181  ret = "HTTP/1.1 201 Created";
182  break;
183  case Response::Accepted:
184  ret = "HTTP/1.1 202 Accepted";
185  break;
186  case Response::NonAuthoritativeInformation:
187  ret = "HTTP/1.1 203 Non-Authoritative Information";
188  break;
189  case Response::NoContent:
190  ret = "HTTP/1.1 204 No Content";
191  break;
192  case Response::ResetContent:
193  ret = "HTTP/1.1 205 Reset Content";
194  break;
195  case Response::PartialContent:
196  ret = "HTTP/1.1 206 Partial Content";
197  break;
198  case Response::MultipleChoices:
199  ret = "HTTP/1.1 300 Multiple Choices";
200  break;
201  case Response::UseProxy:
202  ret = "HTTP/1.1 305 Use Proxy";
203  break;
204  case Response::PaymentRequired:
205  ret = "HTTP/1.1 402 Payment Required";
206  break;
207  case Response::NotAcceptable:
208  ret = "HTTP/1.1 406 Not Acceptable";
209  break;
210  case Response::ProxyAuthenticationRequired:
211  ret = "HTTP/1.1 407 Proxy Authentication Required";
212  break;
213  case Response::Conflict:
214  ret = "HTTP/1.1 409 Conflict";
215  break;
216  case Response::Gone:
217  ret = "HTTP/1.1 410 Gone";
218  break;
219  case Response::LengthRequired:
220  ret = "HTTP/1.1 411 Length Required";
221  break;
222  case Response::PreconditionFailed:
223  ret = "HTTP/1.1 412 Precondition Failed";
224  break;
225  case Response::RequestEntityTooLarge:
226  ret = "HTTP/1.1 413 Request Entity Too Large";
227  break;
228  case Response::RequestURITooLong:
229  ret = "HTTP/1.1 414 Request-URI Too Long";
230  break;
231  case Response::UnsupportedMediaType:
232  ret = "HTTP/1.1 415 Unsupported Media Type";
233  break;
234  case Response::RequestedRangeNotSatisfiable:
235  ret = "HTTP/1.1 416 Requested Range Not Satisfiable";
236  break;
237  case Response::ExpectationFailed:
238  ret = "HTTP/1.1 417 Expectation Failed";
239  break;
240  case Response::NotImplemented:
241  ret = "HTTP/1.1 501 Not Implemented";
242  break;
243  case Response::BadGateway:
244  ret = "HTTP/1.1 502 Bad Gateway";
245  break;
246  case Response::ServiceUnavailable:
247  ret = "HTTP/1.1 503 Service Unavailable";
248  break;
249  case Response::MultiStatus:
250  ret = "HTTP/1.1 207 Multi-Status";
251  break;
252  case Response::GatewayTimeout:
253  ret = "HTTP/1.1 504 Gateway Timeout";
254  break;
255  case Response::HTTPVersionNotSupported:
256  ret = "HTTP/1.1 505 HTTP Version Not Supported";
257  break;
258  case Response::BandwidthLimitExceeded:
259  ret = "HTTP/1.1 509 Bandwidth Limit Exceeded";
260  break;
261  default:
262  ret = "HTTP/1.1 000 Unknown Status";
263  break;
264  }
265 
266  if (len) {
267  *len = int(strlen(ret));
268  }
269  return ret;
270 }
271 
273 {
274  Q_D(Engine);
275  return d->app->defaultHeaders();
276 }
277 
279 {
280  Q_D(Engine);
281  d->app->handleRequest(request);
282 }
283 
284 QVariantMap Engine::opts() const
285 {
286  Q_D(const Engine);
287  return d->opts;
288 }
289 
290 QVariantMap Engine::config(const QString &entity) const
291 {
292  Q_D(const Engine);
293  return d->config.value(entity).toMap();
294 }
295 
296 void Engine::setConfig(const QVariantMap &config)
297 {
298  Q_D(Engine);
299  d->config = config;
300 }
301 
302 QVariantMap Engine::loadIniConfig(const QString &filename)
303 {
304  QVariantMap ret;
305  QSettings settings(filename, QSettings::IniFormat);
306  if (settings.status() != QSettings::NoError) {
307  qCWarning(CUTELYST_ENGINE) << "Failed to load INI file:" << settings.status();
308  return ret;
309  }
310 
311  const auto groups = settings.childGroups();
312  for (const QString &group : groups) {
313  QVariantMap configGroup;
314  settings.beginGroup(group);
315  const auto child = settings.childKeys();
316  for (const QString &key : child) {
317  configGroup.insert(key, settings.value(key));
318  }
319  settings.endGroup();
320  ret.insert(group, configGroup);
321  }
322 
323  return ret;
324 }
325 
326 QVariantMap Engine::loadJsonConfig(const QString &filename)
327 {
328  QVariantMap ret;
329  QFile file(filename);
330  if (!file.open(QIODevice::ReadOnly)) {
331  return ret;
332  }
334 
335  ret = doc.toVariant().toMap();
336 
337  return ret;
338 }
339 
340 #include "moc_engine.cpp"
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QStringList childKeys() const const
void endGroup()
void setConfig(const QVariantMap &config)
Definition: engine.cpp:296
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
iterator insert(const_iterator before, parameter_type value)
static const char * httpStatusMessage(quint16 status, int *len=nullptr)
Definition: engine.cpp:131
void processRequest(EngineRequest *request)
Definition: engine.cpp:278
bool initApplication()
initApplication
Definition: engine.cpp:95
QThread * thread() const const
QVariant value(QAnyStringView key) const const
bool postForkApplication()
postForkApplication
Definition: engine.cpp:112
static QVariantMap loadIniConfig(const QString &filename)
Definition: engine.cpp:302
qint64 currentMSecsSinceEpoch()
QString number(double n, char format, int precision)
Engine(Application *app, int workerCore, const QVariantMap &opts)
Definition: engine.cpp:41
QVariantMap opts() const
Definition: engine.cpp:284
QVariantMap config(const QString &entity) const
user configuration for the application
Definition: engine.cpp:290
QByteArray readAll()
QStringList childGroups() const const
void processRequestAsync(Cutelyst::EngineRequest *request)
void setObjectName(QAnyStringView name)
static QVariantMap loadJsonConfig(const QString &filename)
Definition: engine.cpp:326
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
QVariant toVariant() const const
Status status() const const
QMap< QString, QVariant > toMap() const const
Application * app() const
application
Definition: engine.cpp:63
QThread * currentThread()
virtual quint64 time()
Definition: engine.cpp:126
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
The Cutelyst Application.
Definition: application.h:42
Headers & defaultHeaders()
Definition: engine.cpp:272
QueuedConnection
The Cutelyst Engine
Definition: engine.h:20
int workerCore() const
Each worker process migth have a number of worker cores (threads), a single process with two worker ...
Definition: engine.cpp:89
void beginGroup(QAnyStringView prefix)