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