cutelyst  3.9.1
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
application.cpp
1 /*
2  * SPDX-FileCopyrightText: (C) 2013-2022 Daniel Nicoletti <dantti12@gmail.com>
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 #include "application_p.h"
6 #include "common.h"
7 #include "config.h"
8 #include "context_p.h"
9 #include "controller.h"
10 #include "controller_p.h"
11 #include "dispatchtype.h"
12 #include "enginerequest.h"
13 #include "request.h"
14 #include "request_p.h"
15 #include "response.h"
16 #include "response_p.h"
17 #include "stats.h"
18 #include "utils.h"
19 #include "view.h"
20 
21 #include <QtCore/QCoreApplication>
22 #include <QtCore/QDataStream>
23 #include <QtCore/QDir>
24 #include <QtCore/QFileInfo>
25 #include <QtCore/QLocale>
26 #include <QtCore/QPluginLoader>
27 #include <QtCore/QStringList>
28 #include <QtCore/QTranslator>
29 
30 Q_LOGGING_CATEGORY(CUTELYST_DISPATCHER, "cutelyst.dispatcher", QtWarningMsg)
31 Q_LOGGING_CATEGORY(CUTELYST_DISPATCHER_PATH, "cutelyst.dispatcher.path", QtWarningMsg)
32 Q_LOGGING_CATEGORY(CUTELYST_DISPATCHER_CHAINED, "cutelyst.dispatcher.chained", QtWarningMsg)
33 Q_LOGGING_CATEGORY(CUTELYST_CONTROLLER, "cutelyst.controller", QtWarningMsg)
34 Q_LOGGING_CATEGORY(CUTELYST_CORE, "cutelyst.core", QtWarningMsg)
35 Q_LOGGING_CATEGORY(CUTELYST_ENGINE, "cutelyst.engine", QtWarningMsg)
36 Q_LOGGING_CATEGORY(CUTELYST_UPLOAD, "cutelyst.upload", QtWarningMsg)
37 Q_LOGGING_CATEGORY(CUTELYST_MULTIPART, "cutelyst.multipart", QtWarningMsg)
38 Q_LOGGING_CATEGORY(CUTELYST_VIEW, "cutelyst.view", QtWarningMsg)
39 Q_LOGGING_CATEGORY(CUTELYST_REQUEST, "cutelyst.request", QtWarningMsg)
40 Q_LOGGING_CATEGORY(CUTELYST_RESPONSE, "cutelyst.response", QtWarningMsg)
41 Q_LOGGING_CATEGORY(CUTELYST_STATS, "cutelyst.stats", QtWarningMsg)
42 Q_LOGGING_CATEGORY(CUTELYST_COMPONENT, "cutelyst.component", QtWarningMsg)
43 
44 using namespace Cutelyst;
45 
47  : QObject(parent)
48  , d_ptr(new ApplicationPrivate)
49 {
50  Q_D(Application);
51 
52  d->q_ptr = this;
53 
54  qRegisterMetaType<ParamsMultiMap>();
55 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
56  qRegisterMetaTypeStreamOperators<ParamsMultiMap>("ParamsMultiMap");
57 #endif
58 
59  d->dispatcher = new Dispatcher(this);
60 
61  loadTranslations(QStringLiteral("cutelystcore"));
62 }
63 
64 Application::~Application()
65 {
66  delete d_ptr;
67 }
68 
70 {
71  qCDebug(CUTELYST_CORE) << "Default Application::init called on pid:"
73  return true;
74 }
75 
77 {
78  qCDebug(CUTELYST_CORE) << "Default Application::postFork called on pid:"
80  return true;
81 }
82 
84 {
85  Q_D(Application);
86  return d->headers;
87 }
88 
90 {
91  Q_D(Application);
92  d->headers.setHeader(QStringLiteral("X_CUTELYST"), QStringLiteral(VERSION));
93 }
94 
96 {
97  Q_D(Application);
98  if (d->plugins.contains(plugin)) {
99  return false;
100  }
101  d->plugins.append(plugin);
102  return true;
103 }
104 
106 {
107  Q_D(Application);
108  const auto name = QString::fromLatin1(controller->metaObject()->className());
109  if (d->controllersHash.contains(name)) {
110  return false;
111  }
112  d->controllersHash.insert(name, controller);
113  d->controllers.append(controller);
114  return true;
115 }
116 
118 {
119  Q_D(Application);
120  if (d->views.contains(view->name())) {
121  qCWarning(CUTELYST_CORE) << "Not registering View." << view->metaObject()->className()
122  << "There is already a view with this name:" << view->name();
123  return false;
124  }
125  d->views.insert(view->name(), view);
126  return true;
127 }
128 
130 {
131  Q_D(Application);
132  if (d->dispatchers.contains(dispatcher)) {
133  return false;
134  }
135  d->dispatchers.append(dispatcher);
136  return true;
137 }
138 
140 {
141  Q_D(Application);
142  auto it = d->factories.constFind(name);
143  if (it != d->factories.constEnd()) {
144  ComponentFactory *factory = it.value();
145  if (factory) {
146  return factory->createComponent(parent);
147  } else {
148  return nullptr;
149  }
150  }
151 
152  const QByteArrayList dirs = QByteArrayList{QByteArrayLiteral(CUTELYST_PLUGINS_DIR)} +
153  qgetenv("CUTELYST_PLUGINS_DIR").split(';');
154  for (const QByteArray &dir : dirs) {
155  Component *component = d->createComponentPlugin(name, parent, QString::fromLocal8Bit(dir));
156  if (component) {
157  return component;
158  }
159  }
160  qCDebug(CUTELYST_CORE) << "Did not find plugin" << name << "on" << dirs << "for" << parent;
161 
162  return nullptr;
163 }
164 
165 const char *Application::cutelystVersion() noexcept
166 {
167  return VERSION;
168 }
169 
171 {
172  Q_D(const Application);
173  return d->controllers;
174 }
175 
176 View *Application::view(const QString &name) const
177 {
178  Q_D(const Application);
179  return d->views.value(name);
180 }
181 
183 {
184  Q_D(const Application);
185  return d->views.value(name);
186 }
187 
188 QVariant Application::config(const QString &key, const QVariant &defaultValue) const
189 {
190  Q_D(const Application);
191  auto it = d->config.constFind(key);
192  if (it != d->config.constEnd()) {
193  return it.value();
194  }
195  return defaultValue;
196 }
197 
199 {
200  Q_D(const Application);
201  return d->dispatcher;
202 }
203 
205 {
206  Q_D(const Application);
207  return d->dispatcher->dispatchers();
208 }
209 
211 {
212  Q_D(const Application);
213  return d->plugins;
214 }
215 
216 QVariantMap Application::config() const noexcept
217 {
218  Q_D(const Application);
219  return d->config;
220 }
221 
223 {
224  QDir home = config(QStringLiteral("home")).toString();
225  return home.absoluteFilePath(path);
226 }
227 
229 {
230  QDir home = config(QStringLiteral("home")).toString();
231  return home.absoluteFilePath(path.join(u'/'));
232 }
233 
234 bool Cutelyst::Application::inited() const noexcept
235 {
236  Q_D(const Application);
237  return d->init;
238 }
239 
241 {
242  Q_D(const Application);
243  return d->engine;
244 }
245 
246 void Application::setConfig(const QString &key, const QVariant &value)
247 {
248  Q_D(Application);
249  d->config.insert(key, value);
250 }
251 
253 {
254  Q_D(Application);
255 
256  if (d->init) {
257  return true;
258  }
259  d->init = true;
260 
261  d->useStats = CUTELYST_STATS().isDebugEnabled();
262  d->engine = engine;
263  d->config = engine->config(QLatin1String("Cutelyst"));
264 
265  d->setupHome();
266 
267  // Call the virtual application init
268  // to setup Controllers plugins stuff
269  if (init()) {
270  d->setupChildren(children());
271 
272  bool zeroCore = engine->workerCore() == 0;
273 
274  QVector<QStringList> tablePlugins;
275  const auto plugins = d->plugins;
276  for (Plugin *plugin : plugins) {
277  if (plugin->objectName().isEmpty()) {
278  plugin->setObjectName(QString::fromLatin1(plugin->metaObject()->className()));
279  }
280  tablePlugins.append({plugin->objectName()});
281  // Configure plugins
282  plugin->setup(this);
283  }
284 
285  if (zeroCore && !tablePlugins.isEmpty()) {
286  qCDebug(CUTELYST_CORE)
287  << Utils::buildTable(tablePlugins, QStringList(), QLatin1String("Loaded plugins:"))
288  .constData();
289  }
290 
291  if (zeroCore) {
292  QVector<QStringList> tableDataHandlers;
293  tableDataHandlers.append({QLatin1String("application/x-www-form-urlencoded")});
294  tableDataHandlers.append({QLatin1String("application/json")});
295  tableDataHandlers.append({QLatin1String("multipart/form-data")});
296  qCDebug(CUTELYST_CORE)
297  << Utils::buildTable(tableDataHandlers,
298  QStringList(),
299  QLatin1String("Loaded Request Data Handlers:"))
300  .constData();
301 
302  qCDebug(CUTELYST_CORE) << "Loaded dispatcher"
303  << QString::fromLatin1(d->dispatcher->metaObject()->className());
304  qCDebug(CUTELYST_CORE)
305  << "Using engine" << QString::fromLatin1(d->engine->metaObject()->className());
306  }
307 
308  QString home = d->config.value(QLatin1String("home")).toString();
309  if (home.isEmpty()) {
310  if (zeroCore) {
311  qCDebug(CUTELYST_CORE) << "Couldn't find home";
312  }
313  } else {
314  QFileInfo homeInfo(home);
315  if (homeInfo.isDir()) {
316  if (zeroCore) {
317  qCDebug(CUTELYST_CORE) << "Found home" << home;
318  }
319  } else {
320  if (zeroCore) {
321  qCDebug(CUTELYST_CORE) << "Home" << home << "doesn't exist";
322  }
323  }
324  }
325 
326  QVector<QStringList> table;
327  QStringList controllerNames = d->controllersHash.keys();
328  controllerNames.sort();
329  for (const QString &controller : controllerNames) {
330  table.append({controller, QLatin1String("Controller")});
331  }
332 
333  const auto views = d->views;
334  for (View *view : views) {
335  if (view->reverse().isEmpty()) {
336  const QString className = QString::fromLatin1(view->metaObject()->className()) +
337  QLatin1String("->execute");
338  view->setReverse(className);
339  }
340  table.append({view->reverse(), QLatin1String("View")});
341  }
342 
343  if (zeroCore && !table.isEmpty()) {
344  qCDebug(CUTELYST_CORE)
345  << Utils::buildTable(table,
346  {QLatin1String("Class"), QLatin1String("Type")},
347  QLatin1String("Loaded components:"))
348  .constData();
349  }
350 
351  const auto controllers = d->controllers;
352  for (Controller *controller : controllers) {
353  controller->d_ptr->init(this, d->dispatcher);
354  }
355 
356  d->dispatcher->setupActions(d->controllers, d->dispatchers, d->engine->workerCore() == 0);
357 
358  if (zeroCore) {
359  qCInfo(CUTELYST_CORE) << qPrintable(
360  QString::fromLatin1("%1 powered by Cutelyst %2, Qt %3.")
363  QLatin1String(qVersion())));
364  }
365 
366  Q_EMIT preForked(this);
367 
368  return true;
369  }
370 
371  return false;
372 }
373 
375 {
376  Q_D(Application);
377 
378  Engine *engine = d->engine;
379 
380  auto priv = new ContextPrivate(this, engine, d->dispatcher, d->plugins);
381  auto c = new Context(priv);
382 
383  request->context = c;
384  priv->engineRequest = request;
385  priv->response = new Response(d->headers, request);
386  priv->request = new Request(request);
387 
388  if (d->useStats) {
389  priv->stats = new Stats(request);
390  }
391 
392  // Process request
393  bool skipMethod = false;
394  Q_EMIT beforePrepareAction(c, &skipMethod);
395 
396  if (!skipMethod) {
397  static bool log = CUTELYST_REQUEST().isEnabled(QtDebugMsg);
398  if (log) {
399  d->logRequest(priv->request);
400  }
401 
402  d->dispatcher->prepareAction(c);
403 
405 
406  d->dispatcher->dispatch(c);
407 
408  if (request->status & EngineRequest::Async) {
409  return;
410  }
411 
413  }
414 
415  c->finalize();
416 }
417 
419 {
420  Q_D(Application);
421 
422  if (!postFork()) {
423  return false;
424  }
425 
426  const auto controllers = d->controllers;
427  for (Controller *controller : controllers) {
428  if (!controller->postFork(this)) {
429  return false;
430  }
431  }
432 
433  Q_EMIT postForked(this);
434 
435  return true;
436 }
437 
438 void Application::addTranslator(const QLocale &locale, QTranslator *translator)
439 {
440  Q_D(Application);
441  Q_ASSERT_X(translator, "add translator to application", "invalid QTranslator object");
442  auto it = d->translators.find(locale);
443  if (it != d->translators.end()) {
444  it.value().prepend(translator);
445  } else {
446  d->translators.insert(locale, QVector<QTranslator *>(1, translator));
447  }
448 }
449 
450 void Application::addTranslator(const QString &locale, QTranslator *translator)
451 {
452  addTranslator(QLocale(locale), translator);
453 }
454 
455 void Application::addTranslators(const QLocale &locale, const QVector<QTranslator *> &translators)
456 {
457  Q_D(Application);
458  Q_ASSERT_X(!translators.empty(), "add translators to application", "empty translators vector");
459  auto transIt = d->translators.find(locale);
460  if (transIt != d->translators.end()) {
461  for (auto it = translators.crbegin(); it != translators.crend(); ++it) {
462  transIt.value().prepend(*it);
463  }
464  } else {
465  d->translators.insert(locale, translators);
466  }
467 }
468 
469 static void replacePercentN(QString *result, int n)
470 {
471  if (n >= 0) {
472  auto percentPos = 0;
473  auto len = 0;
474  while ((percentPos = result->indexOf(u'%', percentPos + len)) != -1) {
475  len = 1;
476  QString fmt;
477  if (result->at(percentPos + len) == u'L') {
478  ++len;
479  fmt = QStringLiteral("%L1");
480  } else {
481  fmt = QStringLiteral("%1");
482  }
483  if (result->at(percentPos + len) == u'n') {
484  fmt = fmt.arg(n);
485  ++len;
486  result->replace(percentPos, len, fmt);
487  len = fmt.length();
488  }
489  }
490  }
491 }
492 
494  const char *context,
495  const char *sourceText,
496  const char *disambiguation,
497  int n) const
498 {
499  QString result;
500 
501  if (!sourceText) {
502  return result;
503  }
504 
505  Q_D(const Application);
506 
507  const QVector<QTranslator *> translators = d->translators.value(locale);
508  if (translators.empty()) {
509  result = QString::fromUtf8(sourceText);
510  replacePercentN(&result, n);
511  return result;
512  }
513 
514  for (QTranslator *translator : translators) {
515  result = translator->translate(context, sourceText, disambiguation, n);
516  if (!result.isEmpty()) {
517  break;
518  }
519  }
520 
521  if (result.isEmpty()) {
522  result = QString::fromUtf8(sourceText);
523  }
524 
525  replacePercentN(&result, n);
526  return result;
527 }
528 
530  const QString &directory,
531  const QString &prefix,
532  const QString &suffix)
533 {
534  loadTranslationsFromDir(filename, directory, prefix, suffix);
535 }
536 
538  const QString &directory,
539  const QString &prefix,
540  const QString &suffix)
541 {
542  QVector<QLocale> locales;
543 
544  if (Q_LIKELY(!filename.isEmpty())) {
545  const QString _dir = directory.isEmpty() ? QStringLiteral(I18NDIR) : directory;
546  const QDir i18nDir(_dir);
547  if (Q_LIKELY(i18nDir.exists())) {
548  const QString _prefix = prefix.isEmpty() ? QStringLiteral(".") : prefix;
549  const QString _suffix = suffix.isEmpty() ? QStringLiteral(".qm") : suffix;
550  const QStringList namesFilter = QStringList({filename + _prefix + u'*' + _suffix});
551 
552  const QFileInfoList tsFiles = i18nDir.entryInfoList(namesFilter, QDir::Files);
553  if (Q_LIKELY(!tsFiles.empty())) {
554  locales.reserve(tsFiles.size());
555  for (const QFileInfo &ts : tsFiles) {
556  const QString fn = ts.fileName();
557  const int prefIdx = fn.indexOf(_prefix);
558  const QString locString =
559  fn.mid(prefIdx + _prefix.length(),
560  fn.length() - prefIdx - _suffix.length() - _prefix.length());
561  QLocale loc(locString);
562  if (Q_LIKELY(loc.language() != QLocale::C)) {
563  auto trans = new QTranslator(this);
564  if (Q_LIKELY(trans->load(loc, filename, _prefix, _dir))) {
565  addTranslator(loc, trans);
566  locales.append(loc);
567  qCDebug(CUTELYST_CORE) << "Loaded translations for" << loc << "from"
568  << ts.absoluteFilePath();
569  } else {
570  delete trans;
571  qCWarning(CUTELYST_CORE) << "Can not load translations for" << loc
572  << "from" << ts.absoluteFilePath();
573  }
574  } else {
575  qCWarning(CUTELYST_CORE)
576  << "Can not load translations for invalid locale string" << locString;
577  }
578  }
579  locales.squeeze();
580  } else {
581  qCWarning(CUTELYST_CORE)
582  << "Can not find translation files for" << filename << "in directory" << _dir;
583  }
584  } else {
585  qCWarning(CUTELYST_CORE)
586  << "Can not load translations from not existing directory:" << _dir;
587  }
588  } else {
589  qCWarning(CUTELYST_CORE) << "Can not load translations for empty file name.";
590  }
591 
592  return locales;
593 }
594 
596  const QString &filename)
597 {
598  QVector<QLocale> locales;
599 
600  if (Q_LIKELY(!directory.isEmpty() && !filename.isEmpty())) {
601  const QDir dir(directory);
602  if (Q_LIKELY(dir.exists())) {
603  const auto dirs = dir.entryList(QDir::AllDirs);
604  if (Q_LIKELY(!dirs.empty())) {
605  locales.reserve(dirs.size());
606  for (const QString &subDir : dirs) {
607  const QString relFn = subDir + u'/' + filename;
608  if (dir.exists(relFn)) {
609  const QLocale l(subDir);
610  if (Q_LIKELY(l.language() != QLocale::C)) {
611  auto trans = new QTranslator(this);
612  const QFileInfo fi(dir, relFn);
613  if (Q_LIKELY(trans->load(
614  l, fi.baseName(), QString(), fi.absolutePath(), fi.suffix()))) {
615  addTranslator(l, trans);
616  locales.append(l);
617  qCDebug(CUTELYST_CORE) << "Loaded translations for" << l << "from"
618  << fi.absoluteFilePath();
619  } else {
620  delete trans;
621  qCWarning(CUTELYST_CORE) << "Can not load translations for" << l
622  << "from" << fi.absoluteFilePath();
623  }
624  } else {
625  qCWarning(CUTELYST_CORE)
626  << "Can not load translations for invalid locale string:" << subDir;
627  }
628  }
629  }
630  locales.squeeze();
631  } else {
632  qCWarning(CUTELYST_CORE) << "Can not find locale dirs under" << directory;
633  }
634  } else {
635  qCWarning(CUTELYST_CORE)
636  << "Can not load translations from not existing directory:" << directory;
637  }
638  } else {
639  qCWarning(CUTELYST_CORE)
640  << "Can not load translations for empty file name or directory name";
641  }
642 
643  return locales;
644 }
645 
646 void Cutelyst::ApplicationPrivate::setupHome()
647 {
648  // Hook the current directory in config if "home" is not set
649  if (!config.contains(QLatin1String("home"))) {
650  config.insert(QStringLiteral("home"), QDir::currentPath());
651  }
652 
653  if (!config.contains(QLatin1String("root"))) {
654  QDir home = config.value(QLatin1String("home")).toString();
655  config.insert(QStringLiteral("root"), home.absoluteFilePath(QLatin1String("root")));
656  }
657 }
658 
659 void ApplicationPrivate::setupChildren(const QObjectList &children)
660 {
661  Q_Q(Application);
662  for (QObject *child : children) {
663  auto controller = qobject_cast<Controller *>(child);
664  if (controller) {
665  q->registerController(controller);
666  continue;
667  }
668 
669  auto plugin = qobject_cast<Plugin *>(child);
670  if (plugin) {
671  q->registerPlugin(plugin);
672  continue;
673  }
674 
675  auto view = qobject_cast<View *>(child);
676  if (view) {
677  q->registerView(view);
678  continue;
679  }
680 
681  auto dispatchType = qobject_cast<DispatchType *>(child);
682  if (dispatchType) {
683  q->registerDispatcher(dispatchType);
684  continue;
685  }
686  }
687 }
688 
689 void Cutelyst::ApplicationPrivate::logRequest(Request *req)
690 {
691  QString path = req->path();
692  if (path.isEmpty()) {
693  path = QStringLiteral("/");
694  }
695  qCDebug(CUTELYST_REQUEST) << req->method() << "request for" << path << "from"
696  << req->addressString();
697 
698  ParamsMultiMap params = req->queryParameters();
699  if (!params.isEmpty()) {
700  logRequestParameters(params, QLatin1String("Query Parameters are:"));
701  }
702 
703  params = req->bodyParameters();
704  if (!params.isEmpty()) {
705  logRequestParameters(params, QLatin1String("Body Parameters are:"));
706  }
707 
708  const auto uploads = req->uploads();
709  if (!uploads.isEmpty()) {
710  logRequestUploads(uploads);
711  }
712 }
713 
714 void Cutelyst::ApplicationPrivate::logRequestParameters(const ParamsMultiMap &params,
715  const QString &title)
716 {
717  QVector<QStringList> table;
718  auto it = params.constBegin();
719  while (it != params.constEnd()) {
720  table.append({it.key(), it.value()});
721  ++it;
722  }
723  qCDebug(CUTELYST_REQUEST) << Utils::buildTable(table,
724  {
725  QLatin1String("Parameter"),
726  QLatin1String("Value"),
727  },
728  title)
729  .constData();
730 }
731 
732 void Cutelyst::ApplicationPrivate::logRequestUploads(const QVector<Cutelyst::Upload *> &uploads)
733 {
734  QVector<QStringList> table;
735  for (Upload *upload : uploads) {
736  table.append({upload->name(),
737  upload->filename(),
738  upload->contentType(),
739  QString::number(upload->size())});
740  }
741  qCDebug(CUTELYST_REQUEST) << Utils::buildTable(table,
742  {
743  QLatin1String("Parameter"),
744  QLatin1String("Filename"),
745  QLatin1String("Type"),
746  QLatin1String("Size"),
747  },
748  QLatin1String("File Uploads are:"))
749  .constData();
750 }
751 
752 Component *ApplicationPrivate::createComponentPlugin(const QString &name,
753  QObject *parent,
754  const QString &directory)
755 {
756  Component *component = nullptr;
757 
758  QDir pluginsDir(directory);
759  QPluginLoader loader;
760  ComponentFactory *factory = nullptr;
761  const auto plugins = pluginsDir.entryList(QDir::Files);
762  for (const QString &fileName : plugins) {
763  loader.setFileName(pluginsDir.absoluteFilePath(fileName));
764  const QJsonObject json = loader.metaData()[QLatin1String("MetaData")].toObject();
765  if (json[QLatin1String("name")].toString() == name) {
766  QObject *plugin = loader.instance();
767  if (plugin) {
768  factory = qobject_cast<ComponentFactory *>(plugin);
769  if (!factory) {
770  qCCritical(CUTELYST_CORE)
771  << "Could not create a factory for" << loader.fileName();
772  } else {
773  component = factory->createComponent(parent);
774  }
775  break;
776  } else {
777  qCCritical(CUTELYST_CORE)
778  << "Could not load plugin" << loader.fileName() << loader.errorString();
779  }
780  }
781  }
782 
783  if (factory) {
784  factories.insert(name, factory);
785  }
786 
787  return component;
788 }
789 
790 #include "moc_application.cpp"
QVector< DispatchType * > dispatchers() const noexcept
void setConfig(const QString &key, const QVariant &value)
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QString & append(QChar ch)
QVariantMap config() const noexcept
QVector::const_reverse_iterator crbegin() const const
void postForked(Cutelyst::Application *app)
void append(const T &value)
void setReverse(const QString &reverse)
Definition: component.cpp:51
QMap::const_iterator constBegin() const const
const QObjectList & children() const const
void insert(int i, T &&value)
View * view(const QString &name) const
virtual const QMetaObject * metaObject() const const
bool registerView(View *view)
void loadTranslations(const QString &filename, const QString &directory=QString(), const QString &prefix=QString(), const QString &suffix=QString())
QVector< Controller * > controllers() const noexcept
QString join(const QString &separator) const const
QString currentPath()
QJsonObject metaData() const const
T plugin()
Returns the registered plugin that casts to the template type T.
Definition: application.h:107
void setFileName(const QString &fileName)
void addXCutelystVersionHeader()
Definition: application.cpp:89
bool setup(Engine *engine)
Called by the Engine to setup the internal data.
void addTranslators(const QLocale &locale, const QVector< QTranslator *> &translators)
void preForked(Cutelyst::Application *app)
The Cutelyst Component base class.
Definition: component.h:25
void handleRequest(Cutelyst::EngineRequest *request)
Called by the Engine to handle a new Request object.
T value(int i) const const
Headers & defaultHeaders() noexcept
Definition: application.cpp:83
Cutelyst Upload handles file upload request
Definition: upload.h:22
ParamsMultiMap bodyParameters() const
Definition: request.cpp:216
The Cutelyst Context.
Definition: context.h:38
QString number(int n, int base)
QString fromLocal8Bit(const char *str, int size)
bool exists() const const
Cutelyst Controller base class
Definition: controller.h:87
QVector< Upload * > uploads() const
Definition: request.cpp:377
QString fromUtf8(const char *str, int size)
QString & insert(int position, QChar ch)
bool registerController(Controller *controller)
QString addressString() const
Definition: request.cpp:39
bool isDir() const const
virtual bool init()
Definition: application.cpp:69
QString name() const
Definition: component.cpp:33
Component * createComponentPlugin(const QString &name, QObject *parent=nullptr)
QVector< Plugin * > plugins() const noexcept
void beforePrepareAction(Cutelyst::Context *c, bool *skipMethod)
QFileInfoList entryInfoList(QDir::Filters filters, QDir::SortFlags sort) const const
Context * context
The Cutelyst::Context of this request.
QVariantMap config(const QString &entity) const
user configuration for the application
Definition: engine.cpp:290
QString absoluteFilePath() const const
bool isEmpty() const const
QMap::const_iterator constEnd() const const
QObject * instance()
void addTranslator(const QLocale &locale, QTranslator *translator)
QLocale::Language language() const const
QString pathTo(const QString &path) const
qint64 applicationPid()
QString errorString() const const
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
QString reverse() const
Definition: component.cpp:45
bool registerDispatcher(DispatchType *dispatcher)
void squeeze()
void reserve(int size)
const char * className() const const
void beforeDispatch(Cutelyst::Context *c)
ParamsMultiMap queryParameters() const
Definition: request.cpp:252
Application(QObject *parent=nullptr)
Definition: application.cpp:46
QString & replace(int position, int n, QChar after)
bool enginePostFork()
Called by the Engine once post fork happened.
virtual bool postFork()
Definition: application.cpp:76
void afterDispatch(Cutelyst::Context *c)
QString mid(int position, int n) const const
QString suffix() const const
Dispatcher * dispatcher() const noexcept
bool isEmpty() const const
bool inited() const noexcept
QStringList entryList(QDir::Filters filters, QDir::SortFlags sort) const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
const QChar at(int position) const const
Cutelyst View abstract view component
Definition: view.h:21
Status status
Connection status.
QString absoluteFilePath(const QString &fileName) const const
int length() const const
QString fromLatin1(const char *str, int size)
void sort(Qt::CaseSensitivity cs)
The Cutelyst Application.
Definition: application.h:42
bool isEmpty() const const
Engine * engine() const noexcept
bool registerPlugin(Plugin *plugin)
Definition: application.cpp:95
QString absolutePath() const const
virtual Component * createComponent(QObject *parent=nullptr)=0
QObject * parent() const const
QVector< QLocale > loadTranslationsFromDir(const QString &filename, const QString &directory=QString(), const QString &prefix=QStringLiteral("."), const QString &suffix=QStringLiteral(".qm"))
The Cutelyst Engine
Definition: engine.h:20
QVector< QLocale > loadTranslationsFromDirs(const QString &directory, const QString &filename)
bool empty() const const
The Cutelyst Dispatcher.
Definition: dispatcher.h:27
int workerCore() const
Each worker process migth have a number of worker cores (threads), a single process with two worker ...
Definition: engine.cpp:89
QString translate(const QLocale &locale, const char *context, const char *sourceText, const char *disambiguation=nullptr, int n=-1) const
QString baseName() const const
Q_EMITQ_EMIT
QString applicationName()
QVector::const_reverse_iterator crend() const const
static const char * cutelystVersion() noexcept