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