5 #include "localserver.h" 7 #include "protocolfastcgi.h" 8 #include "protocolhttp.h" 9 #include "protocolhttp2.h" 11 #include "serverengine.h" 13 #include "tcpserverbalancer.h" 16 # include "unixfork.h" 18 # include "windowsfork.h" 22 # include "../EventLoopEPoll/eventdispatcher_epoll.h" 23 # include "systemdnotify.h" 28 #include <QCommandLineParser> 29 #include <QCoreApplication> 31 #include <QLoggingCategory> 32 #include <QMetaProperty> 33 #include <QPluginLoader> 35 #include <QSocketNotifier> 40 Q_LOGGING_CATEGORY(CUTELYST_SERVER,
"cutelyst.server", QtWarningMsg)
46 , d_ptr(new ServerPrivate(this))
50 if (!qEnvironmentVariableIsSet(
"QT_MESSAGE_PATTERN")) {
51 if (qEnvironmentVariableIsSet(
"JOURNAL_STREAM")) {
53 qSetMessagePattern(u
"%{category}[%{type}] %{message}"_qs);
55 qSetMessagePattern(u
"%{pid}:%{threadid} %{category}[%{type}] %{message}"_qs);
60 if (!qEnvironmentVariableIsSet(
"CUTELYST_QT_EVENT_LOOP")) {
61 qCInfo(CUTELYST_SERVER) <<
"Trying to install EPoll event loop";
66 auto cleanUp = [
this]() {
69 d->protoHTTP =
nullptr;
72 d->protoHTTP2 =
nullptr;
75 d->protoFCGI =
nullptr;
80 qDeleteAll(d->servers);
91 std::cout <<
"Cutelyst-Server terminated" << std::endl;
102 qtTrId(
"cutelystd-cli-desc"));
111 qtTrId(
"cutelystd-opt-ini-desc"),
114 qtTrId(
"cutelystd-opt-value-file"));
122 qtTrId(
"cutelystd-opt-json-desc"),
123 qtTrId(
"cutelystd-opt-value-file"));
127 QStringLiteral(
"chdir"),
130 qtTrId(
"cutelystd-opt-chdir-desc"),
133 qtTrId(
"cutelystd-opt-value-directory"));
137 QStringLiteral(
"chdir2"),
140 qtTrId(
"cutelystd-opt-chdir2-desc"),
141 qtTrId(
"cutelystd-opt-value-directory"));
145 QStringLiteral(
"lazy"),
148 qtTrId(
"cutelystd-opt-lazy-desc"));
154 qtTrId(
"cutelystd-opt-application-desc"),
155 qtTrId(
"cutelystd-opt-value-file"));
162 qtTrId(
"cutelystd-opt-threads-desc"),
165 qtTrId(
"cutelystd-opt-threads-value"));
173 qtTrId(
"cutelystd-opt-processes-desc"),
176 qtTrId(
"cutelystd-opt-processes-value"));
183 qtTrId(
"cutelystd-opt-master-desc"));
189 qtTrId(
"cutelystd-opt-listen-desc"),
192 qtTrId(
"cutelystd-opt-value-size"));
198 qtTrId(
"cutelystd-opt-buffer-size-desc"),
201 qtTrId(
"cutelystd-opt-value-bytes"));
208 qtTrId(
"cutelystd-opt-post-buffering-desc"),
209 qtTrId(
"cutelystd-opt-value-bytes"));
213 QStringLiteral(
"post-buffering-bufsize"),
216 qtTrId(
"cutelystd-opt-post-buffering-bufsize-desc"),
217 qtTrId(
"cutelystd-opt-value-bytes"));
220 QCommandLineOption httpSocketOpt({QStringLiteral(
"http-socket"), QStringLiteral(
"h1")},
223 qtTrId(
"cutelystd-opt-http-socket-desc"),
226 qtTrId(
"cutelystd-opt-value-address"));
230 {QStringLiteral(
"http2-socket"), QStringLiteral(
"h2")},
233 qtTrId(
"cutelystd-opt-http2-socket-desc"),
234 qtTrId(
"cutelystd-opt-value-address"));
240 qtTrId(
"cutelystd-opt-http2-header-table-size-desc"),
241 qtTrId(
"cutelystd-opt-value-size"));
242 parser.
addOption(http2HeaderTableSizeOpt);
247 qtTrId(
"cutelystd-opt-upgrade-h2c-desc"));
253 qtTrId(
"cutelystd-opt-https-h2-desc"));
256 QCommandLineOption httpsSocketOpt({QStringLiteral(
"https-socket"), QStringLiteral(
"hs1")},
259 qtTrId(
"cutelystd-opt-https-socket-desc"),
260 qtTrId(
"cutelystd-opt-value-address"));
264 QStringLiteral(
"fastcgi-socket"),
267 qtTrId(
"cutelystd-opt-fastcgi-socket-desc"),
268 qtTrId(
"cutelystd-opt-value-address"));
272 QStringLiteral(
"socket-access"),
275 qtTrId(
"cutelystd-opt-socket-access-desc"),
278 qtTrId(
"cutelystd-opt-socket-access-value"));
281 QCommandLineOption socketTimeout({QStringLiteral(
"socket-timeout"), QStringLiteral(
"z")},
284 qtTrId(
"cutelystd-opt-socket-timeout-desc"),
287 qtTrId(
"cutelystd-opt-socket-timeout-value"));
296 qtTrId(
"cutelystd-opt-static-map-desc"),
299 qtTrId(
"cutelystd-opt-value-static-map"));
306 qtTrId(
"cutelystd-opt-static-map2-desc"),
309 qtTrId(
"cutelystd-opt-value-static-map"));
315 qtTrId(
"cutelystd-opt-auto-restart-desc"));
319 QStringLiteral(
"touch-reload"),
322 qtTrId(
"cutelystd-opt-touch-reload-desc"),
323 qtTrId(
"cutelystd-opt-value-file"));
329 qtTrId(
"cutelystd-opt-tcp-nodelay-desc"));
335 qtTrId(
"cutelystd-opt-so-keepalive-desc"));
342 qtTrId(
"cutelystd-opt-socket-sndbuf-desc"),
343 qtTrId(
"cutelystd-opt-value-bytes"));
350 qtTrId(
"cutelystd-opt-socket-rcvbuf-desc"),
351 qtTrId(
"cutelystd-opt-value-bytes"));
358 qtTrId(
"cutelystd-opt-websocket-max-size-desc"),
361 qtTrId(
"cutelystd-opt-websocket-max-size-value"));
367 qtTrId(
"cutelystd-opt-pidfile-desc"),
370 qtTrId(
"cutelystd-opt-value-pidfile"));
376 qtTrId(
"cutelystd-opt-pidfile2-desc"),
377 qtTrId(
"cutelystd-opt-value-pidfile"));
384 qtTrId(
"cutelystd-opt-stop-desc"),
385 qtTrId(
"cutelystd-opt-value-pidfile"));
391 qtTrId(
"cutelystd-opt-uid-desc"),
394 qtTrId(
"cutelystd-opt-uid-value"));
400 qtTrId(
"cutelystd-opt-gid-desc"),
403 qtTrId(
"cutelystd-opt-gid-value"));
409 qtTrId(
"cutelystd-opt-no-init-groups-desc"));
415 qtTrId(
"cutelystd-opt-chown-socket-desc"),
418 qtTrId(
"cutelystd-opt-chown-socket-value"));
424 qtTrId(
"cutelystd-opt-umask-desc"),
427 qtTrId(
"cutelystd-opt-umask-value"));
431 QStringLiteral(
"cpu-affinity"),
434 qtTrId(
"cutelystd-opt-cpu-affinity-desc"),
437 qtTrId(
"cutelystd-opt-cpu-affinity-value"));
445 qtTrId(
"cutelystd-opt-reuse-port-desc"));
450 QStringLiteral(
"experimental-thread-balancer"),
453 qtTrId(
"cutelystd-opt-experimental-thread-balancer-desc"));
459 qtTrId(
"cutelystd-opt-using-frontend-proxy-desc"));
465 setIni(parser.
values(iniOpt));
467 setJson(parser.
values(jsonOpt));
469 if (parser.
isSet(chdir)) {
470 setChdir(parser.
value(chdir));
473 if (parser.
isSet(chdir2)) {
474 setChdir2(parser.
value(chdir2));
481 if (parser.
isSet(socketAccess)) {
482 setSocketAccess(parser.
value(socketAccess));
485 if (parser.
isSet(socketTimeout)) {
487 auto size = parser.
value(socketTimeout).
toInt(&ok);
488 setSocketTimeout(size);
489 if (!ok || size < 0) {
494 if (parser.
isSet(pidfileOpt)) {
495 setPidfile(parser.
value(pidfileOpt));
498 if (parser.
isSet(pidfile2Opt)) {
499 setPidfile2(parser.
value(pidfile2Opt));
503 if (parser.
isSet(stopOption)) {
504 UnixFork::stopWSGI(parser.
value(stopOption));
511 if (parser.
isSet(uidOption)) {
512 setUid(parser.
value(uidOption));
515 if (parser.
isSet(gidOption)) {
516 setGid(parser.
value(gidOption));
519 if (parser.
isSet(noInitgroupsOption)) {
520 setNoInitgroups(
true);
523 if (parser.
isSet(chownSocketOption)) {
524 setChownSocket(parser.
value(chownSocketOption));
527 if (parser.
isSet(umaskOption)) {
528 setUmask(parser.
value(umaskOption));
531 if (parser.
isSet(cpuAffinityOption)) {
533 auto value = parser.
value(cpuAffinityOption).
toInt(&ok);
534 setCpuAffinity(value);
535 if (!ok || value < 0) {
542 if (parser.
isSet(reusePortOption)) {
547 if (parser.
isSet(lazyOption)) {
551 if (parser.
isSet(listenQueue)) {
553 auto size = parser.
value(listenQueue).
toInt(&ok);
554 setListenQueue(size);
555 if (!ok || size < 1) {
560 if (parser.
isSet(bufferSize)) {
562 auto size = parser.
value(bufferSize).
toInt(&ok);
564 if (!ok || size < 1) {
569 if (parser.
isSet(postBuffering)) {
572 setPostBuffering(size);
573 if (!ok || size < 1) {
578 if (parser.
isSet(postBufferingBufsize)) {
581 setPostBufferingBufsize(size);
582 if (!ok || size < 1) {
595 if (parser.
isSet(autoReload)) {
599 if (parser.
isSet(tcpNoDelay)) {
603 if (parser.
isSet(soKeepAlive)) {
604 setSoKeepalive(
true);
607 if (parser.
isSet(upgradeH2cOpt)) {
611 if (parser.
isSet(httpsH2Opt)) {
615 if (parser.
isSet(socketSndbuf)) {
617 auto size = parser.
value(socketSndbuf).
toInt(&ok);
618 setSocketSndbuf(size);
619 if (!ok || size < 1) {
624 if (parser.
isSet(socketRcvbuf)) {
626 auto size = parser.
value(socketRcvbuf).
toInt(&ok);
627 setSocketRcvbuf(size);
628 if (!ok || size < 1) {
633 if (parser.
isSet(wsMaxSize)) {
635 auto size = parser.
value(wsMaxSize).
toInt(&ok);
636 setWebsocketMaxSize(size);
637 if (!ok || size < 1) {
642 if (parser.
isSet(http2HeaderTableSizeOpt)) {
644 auto size = parser.
value(http2HeaderTableSizeOpt).
toUInt(&ok);
645 setHttp2HeaderTableSize(size);
646 if (!ok || size < 1) {
651 if (parser.
isSet(frontendProxy)) {
652 setUsingFrontendProxy(
true);
655 setHttpSocket(httpSocket() + parser.
values(httpSocketOpt));
657 setHttp2Socket(http2Socket() + parser.
values(http2SocketOpt));
659 setHttpsSocket(httpsSocket() + parser.
values(httpsSocketOpt));
661 setFastcgiSocket(fastcgiSocket() + parser.
values(fastcgiSocketOpt));
663 setStaticMap(staticMap() + parser.
values(staticMapOpt));
665 setStaticMap2(staticMap2() + parser.
values(staticMap2Opt));
667 setTouchReload(touchReload() + parser.
values(touchReloadOpt));
669 d->threadBalancer = parser.
isSet(threadBalancerOpt);
675 std::cout <<
"Cutelyst-Server starting" << std::endl;
677 if (!qEnvironmentVariableIsSet(
"CUTELYST_SERVER_IGNORE_MASTER") && !d->master) {
679 <<
"*** WARNING: you are running Cutelyst-Server without its master process manager ***" 684 if (d->processes == -1 && d->threads == -1) {
685 d->processes = UnixFork::idealProcessCount();
686 d->threads = UnixFork::idealThreadCount() / d->processes;
687 }
else if (d->processes == -1) {
688 d->processes = UnixFork::idealThreadCount();
689 }
else if (d->threads == -1) {
690 d->threads = UnixFork::idealThreadCount();
693 if (d->processes == 0 && d->master) {
696 d->genericFork =
new UnixFork(d->processes, qMax(d->threads, 1), !d->userEventLoop,
this);
698 if (d->processes == -1) {
701 if (d->threads == -1) {
712 if (d->master && d->lazy) {
713 if (d->autoReload && !d->application.isEmpty()) {
714 d->touchReload.append(d->application);
716 d->genericFork->setTouchReload(d->touchReload);
720 if (d->master && !d->genericFork->continueMaster(&ret)) {
725 if (systemdNotify::is_systemd_notify_available()) {
727 sd->setWatchdog(
true, systemdNotify::sd_watchdog_enabled(
true));
729 sd->sendStatus(qApp->applicationName().toLatin1() +
" is ready");
732 connect(d, &ServerPrivate::postForked, sd, [sd] { sd->setWatchdog(
false); });
733 qInfo(CUTELYST_SERVER) <<
"systemd notify detected";
741 if (!d->listenTcpSockets()) {
748 if (!d->writePidFile(d->pidfile)) {
754 bool isListeningLocalSockets =
false;
755 if (!d->chownSocket.isEmpty()) {
756 if (!d->listenLocalSockets()) {
761 isListeningLocalSockets =
true;
764 if (!d->umask.isEmpty() && !UnixFork::setUmask(d->umask.toLatin1())) {
768 if (!UnixFork::setGidUid(d->gid, d->uid, d->noInitgroups)) {
774 if (!isListeningLocalSockets) {
776 d->listenLocalSockets();
782 if (!d->listenTcpSockets()) {
788 if (d->servers.empty()) {
789 std::cout <<
"Please specify a socket to listen to" << std::endl;
795 d->writePidFile(d->pidfile2);
797 if (!d->chdir.isEmpty()) {
798 std::cout <<
"Changing directory to: " << d->chdir.toLatin1().constData() << std::endl;
809 if (!d->setupApplication()) {
816 if (d->userEventLoop) {
821 ret = d->genericFork->exec(d->lazy, d->master);
839 d->userEventLoop =
true;
844 qputenv(
"CUTELYST_SERVER_IGNORE_MASTER", QByteArrayLiteral(
"1"));
846 if (
exec(app) == 0) {
856 if (d->userEventLoop) {
861 ServerPrivate::~ServerPrivate()
868 bool ServerPrivate::listenTcpSockets()
870 if (httpSockets.isEmpty() && httpsSockets.isEmpty() && http2Sockets.isEmpty() &&
871 fastcgiSockets.isEmpty()) {
877 for (
const auto &socket : qAsConst(httpSockets)) {
878 if (!listenTcp(socket, getHttpProto(),
false)) {
884 for (
const auto &socket : qAsConst(httpsSockets)) {
885 if (!listenTcp(socket, getHttpProto(),
true)) {
891 for (
const auto &socket : qAsConst(http2Sockets)) {
892 if (!listenTcp(socket, getHttp2Proto(),
false)) {
898 for (
const auto &socket : qAsConst(fastcgiSockets)) {
899 if (!listenTcp(socket, getFastCgiProto(),
false)) {
907 bool ServerPrivate::listenTcp(
const QString &line,
Protocol *protocol,
bool secure)
914 server->setBalancer(threadBalancer);
915 ret = server->listen(line, protocol, secure);
917 if (ret && server->socketDescriptor()) {
918 auto qEnum = protocol->staticMetaObject.enumerator(0);
919 std::cout << qEnum.valueToKey(static_cast<int>(protocol->type())) <<
" socket " 921 <<
" bound to TCP address " << server->serverName().constData() <<
" fd " 930 bool ServerPrivate::listenLocalSockets()
939 std::vector<int> fds = systemdNotify::listenFds();
942 if (server->listen(fd)) {
943 const QString name = server->serverName();
944 const QString fullName = server->fullServerName();
948 protocol = getHttpProto();
950 protocol = getHttp2Proto();
952 protocol = getFastCgiProto();
954 std::cerr <<
"systemd activated socket does not match any configured socket" 958 server->setProtocol(protocol);
959 server->pauseAccepting();
961 auto qEnum = protocol->staticMetaObject.enumerator(0);
962 std::cout << qEnum.valueToKey(static_cast<int>(protocol->type())) <<
" socket " 964 <<
" bound to LOCAL address " << qPrintable(fullName) <<
" fd " 968 std::cerr <<
"Failed to listen on activated LOCAL FD: " 970 << qPrintable(server->errorString()) << std::endl;
977 const auto httpConst = http;
978 for (
const auto &socket : httpConst) {
979 ret |= listenLocal(socket, getHttpProto());
982 const auto http2Const = http2;
983 for (
const auto &socket : http2Const) {
984 ret |= listenLocal(socket, getHttp2Proto());
987 const auto fastcgiConst = fastcgi;
988 for (
const auto &socket : fastcgiConst) {
989 ret |= listenLocal(socket, getFastCgiProto());
995 bool ServerPrivate::listenLocal(
const QString &line,
Protocol *protocol)
1002 server->setProtocol(protocol);
1003 if (!socketAccess.isEmpty()) {
1005 if (socketAccess.contains(u
'u')) {
1009 if (socketAccess.contains(u
'g')) {
1013 if (socketAccess.contains(u
'o')) {
1016 server->setSocketOptions(options);
1018 server->removeServer(line);
1019 ret = server->listen(line);
1020 server->pauseAccepting();
1022 if (!ret || !server->socket()) {
1023 std::cerr <<
"Failed to listen on LOCAL: " << qPrintable(line) <<
" : " 1024 << qPrintable(server->errorString()) << std::endl;
1029 if (!chownSocket.isEmpty()) {
1030 UnixFork::chownSocket(line, chownSocket);
1033 auto qEnum = protocol->staticMetaObject.enumerator(0);
1034 std::cout << qEnum.valueToKey(static_cast<int>(protocol->type())) <<
" socket " 1036 <<
" bound to LOCAL address " << qPrintable(line) <<
" fd " 1044 void Server::setApplication(
const QString &application)
1049 if (loader.fileName().isEmpty()) {
1050 d->application = application;
1054 d->application = loader.fileName();
1059 QString Server::application()
const 1062 return d->application;
1065 void Server::setThreads(
const QString &threads)
1071 d->threads = qMax(1, threads.
toInt());
1076 QString Server::threads()
const 1079 if (d->threads == -1) {
1080 return QStringLiteral(
"auto");
1085 void Server::setProcesses(
const QString &process)
1092 d->processes = process.
toInt();
1098 QString Server::processes()
const 1101 if (d->processes == -1) {
1102 return QStringLiteral(
"auto");
1107 void Server::setChdir(
const QString &chdir)
1120 void Server::setHttpSocket(
const QStringList &httpSocket)
1123 d->httpSockets = httpSocket;
1130 return d->httpSockets;
1133 void Server::setHttp2Socket(
const QStringList &http2Socket)
1136 d->http2Sockets = http2Socket;
1143 return d->http2Sockets;
1146 void Server::setHttp2HeaderTableSize(quint32 headerTableSize)
1149 d->http2HeaderTableSize = headerTableSize;
1153 quint32 Server::http2HeaderTableSize()
const 1156 return d->http2HeaderTableSize;
1159 void Server::setUpgradeH2c(
bool enable)
1162 d->upgradeH2c = enable;
1166 bool Server::upgradeH2c()
const 1169 return d->upgradeH2c;
1172 void Server::setHttpsH2(
bool enable)
1175 d->httpsH2 = enable;
1179 bool Server::httpsH2()
const 1185 void Server::setHttpsSocket(
const QStringList &httpsSocket)
1188 d->httpsSockets = httpsSocket;
1195 return d->httpsSockets;
1198 void Server::setFastcgiSocket(
const QStringList &fastcgiSocket)
1201 d->fastcgiSockets = fastcgiSocket;
1208 return d->fastcgiSockets;
1211 void Server::setSocketAccess(
const QString &socketAccess)
1214 d->socketAccess = socketAccess;
1218 QString Server::socketAccess()
const 1221 return d->socketAccess;
1224 void Server::setSocketTimeout(
int timeout)
1227 d->socketTimeout = timeout;
1231 int Server::socketTimeout()
const 1234 return d->socketTimeout;
1237 void Server::setChdir2(
const QString &chdir2)
1244 QString Server::chdir2()
const 1253 d->ini.append(files);
1254 d->ini.removeDuplicates();
1257 for (
const QString &file : files) {
1258 if (!d->configLoaded.contains(file)) {
1259 auto fileToLoad = std::make_pair(file, ServerPrivate::ConfigFormat::Ini);
1260 if (!d->configToLoad.contains(fileToLoad)) {
1261 qCDebug(CUTELYST_SERVER) <<
"Enqueue INI config file:" << file;
1262 d->configToLoad.enqueue(fileToLoad);
1279 d->json.append(files);
1280 d->json.removeDuplicates();
1283 for (
const QString &file : files) {
1284 if (!d->configLoaded.contains(file)) {
1285 auto fileToLoad = std::make_pair(file, ServerPrivate::ConfigFormat::Json);
1286 if (!d->configToLoad.contains(fileToLoad)) {
1287 qCDebug(CUTELYST_SERVER) <<
"Enqueue JSON config file:" << file;
1288 d->configToLoad.enqueue(fileToLoad);
1302 void Server::setStaticMap(
const QStringList &staticMap)
1305 d->staticMaps = staticMap;
1312 return d->staticMaps;
1315 void Server::setStaticMap2(
const QStringList &staticMap)
1318 d->staticMaps2 = staticMap;
1325 return d->staticMaps2;
1328 void Server::setMaster(
bool enable)
1331 if (!qEnvironmentVariableIsSet(
"CUTELYST_SERVER_IGNORE_MASTER")) {
1337 bool Server::master()
const 1343 void Server::setAutoReload(
bool enable)
1347 d->autoReload =
true;
1352 bool Server::autoReload()
const 1355 return d->autoReload;
1358 void Server::setTouchReload(
const QStringList &files)
1361 d->touchReload = files;
1368 return d->touchReload;
1371 void Server::setListenQueue(
int size)
1374 d->listenQueue = size;
1378 int Server::listenQueue()
const 1381 return d->listenQueue;
1384 void Server::setBufferSize(
int size)
1388 qCWarning(CUTELYST_SERVER) <<
"Buffer size must be at least 4096 bytes, ignoring";
1391 d->bufferSize = size;
1395 int Server::bufferSize()
const 1398 return d->bufferSize;
1401 void Server::setPostBuffering(qint64 size)
1404 d->postBuffering = size;
1408 qint64 Server::postBuffering()
const 1411 return d->postBuffering;
1414 void Server::setPostBufferingBufsize(qint64 size)
1418 qCWarning(CUTELYST_SERVER) <<
"Post buffer size must be at least 4096 bytes, ignoring";
1421 d->postBufferingBufsize = size;
1425 qint64 Server::postBufferingBufsize()
const 1428 return d->postBufferingBufsize;
1431 void Server::setTcpNodelay(
bool enable)
1434 d->tcpNodelay = enable;
1438 bool Server::tcpNodelay()
const 1441 return d->tcpNodelay;
1444 void Server::setSoKeepalive(
bool enable)
1447 d->soKeepalive = enable;
1451 bool Server::soKeepalive()
const 1454 return d->soKeepalive;
1457 void Server::setSocketSndbuf(
int value)
1460 d->socketSendBuf = value;
1464 int Server::socketSndbuf()
const 1467 return d->socketSendBuf;
1470 void Server::setSocketRcvbuf(
int value)
1473 d->socketReceiveBuf = value;
1477 int Server::socketRcvbuf()
const 1480 return d->socketReceiveBuf;
1483 void Server::setWebsocketMaxSize(
int value)
1486 d->websocketMaxSize = value * 1024;
1490 int Server::websocketMaxSize()
const 1493 return d->websocketMaxSize / 1024;
1496 void Server::setPidfile(
const QString &file)
1503 QString Server::pidfile()
const 1509 void Server::setPidfile2(
const QString &file)
1516 QString Server::pidfile2()
const 1522 void Server::setUid(
const QString &uid)
1537 void Server::setGid(
const QString &gid)
1552 void Server::setNoInitgroups(
bool enable)
1556 d->noInitgroups = enable;
1561 bool Server::noInitgroups()
const 1564 return d->noInitgroups;
1567 void Server::setChownSocket(
const QString &chownSocket)
1571 d->chownSocket = chownSocket;
1576 QString Server::chownSocket()
const 1579 return d->chownSocket;
1582 void Server::setUmask(
const QString &value)
1597 void Server::setCpuAffinity(
int value)
1601 d->cpuAffinity = value;
1606 int Server::cpuAffinity()
const 1609 return d->cpuAffinity;
1612 void Server::setReusePort(
bool enable)
1616 d->reusePort = enable;
1623 bool Server::reusePort()
const 1626 return d->reusePort;
1629 void Server::setLazy(
bool enable)
1636 bool Server::lazy()
const 1642 void Server::setUsingFrontendProxy(
bool enable)
1645 d->usingFrontendProxy = enable;
1649 bool Server::usingFrontendProxy()
const 1652 return d->usingFrontendProxy;
1661 bool ServerPrivate::setupApplication()
1668 std::cout <<
"Loading application: " << application.
toLatin1().
constData() << std::endl;
1671 if (!loader.load()) {
1672 qCCritical(CUTELYST_SERVER) <<
"Could not load application:" << loader.errorString();
1676 QObject *instance = loader.instance();
1678 qCCritical(CUTELYST_SERVER) <<
"Could not get a QObject instance: %s\n" 1679 << loader.errorString();
1685 qCCritical(CUTELYST_SERVER)
1686 <<
"Could not cast Cutelyst::Application from instance: %s\n" 1687 << loader.errorString();
1698 if (!chdir2.isEmpty()) {
1699 std::cout <<
"Changing directory2 to: " << chdir2.toLatin1().constData() << std::endl;
1708 engine = createEngine(localApp, 0);
1709 for (
int i = 1; i < threads; ++i) {
1710 if (createEngine(localApp, i)) {
1711 ++workersNotRunning;
1715 engine = createEngine(localApp, 0);
1716 workersNotRunning = 1;
1720 std::cerr <<
"Application failed to init, cheaping..." << std::endl;
1727 void ServerPrivate::engineShutdown(
ServerEngine *engine)
1729 const auto engineThread = engine->
thread();
1732 engines.erase(std::remove(engines.begin(), engines.end(), engine), engines.end());
1733 checkEngineShutdown();
1735 engineThread->quit();
1737 engines.erase(std::remove(engines.begin(), engines.end(), engine), engines.end());
1740 checkEngineShutdown();
1743 void ServerPrivate::checkEngineShutdown()
1745 if (engines.empty()) {
1746 if (userEventLoop) {
1748 Q_EMIT q->stopped();
1755 void ServerPrivate::workerStarted()
1760 if (--workersNotRunning == 0) {
1765 bool ServerPrivate::postFork(
int workerId)
1770 if (!setupApplication()) {
1771 Q_EMIT q->errorOccured(qtTrId(
"cutelystd-err-fail-setup-app"));
1776 if (engines.size() > 1) {
1777 qCDebug(CUTELYST_SERVER) <<
"Starting threads";
1782 if (thread != qApp->thread()) {
1784 if (!qEnvironmentVariableIsSet(
"CUTELYST_QT_EVENT_LOOP")) {
1793 Q_EMIT postForked(workerId);
1801 qApp->processEvents();
1807 bool ServerPrivate::writePidFile(
const QString &filename)
1813 QFile file(filename);
1815 std::cerr <<
"Failed write pid file " << qPrintable(filename) << std::endl;
1819 std::cout <<
"Writing pidfile to " << qPrintable(filename) << std::endl;
1830 if (workerCore > 0) {
1833 qFatal(
"*** FATAL *** Could not create a NEW instance of your Cutelyst::Application, " 1834 "make sure your constructor has Q_INVOKABLE macro or disable threaded mode.");
1838 auto engine =
new ServerEngine(app, workerCore, opt, q);
1843 &ServerEngine::shutdownCompleted,
1845 &ServerPrivate::engineShutdown,
1851 engine->setServers(servers);
1852 if (!engine->
init()) {
1853 std::cerr <<
"Application failed to init(), cheaping core: " << workerCore << std::endl;
1858 engines.push_back(engine);
1861 if (workerCore > 0) {
1866 auto thread =
new QThread(
this);
1875 void ServerPrivate::loadConfig()
1877 if (loadingConfig) {
1881 loadingConfig =
true;
1883 if (configToLoad.isEmpty()) {
1884 loadingConfig =
false;
1888 auto fileToLoad = configToLoad.dequeue();
1890 if (fileToLoad.first.isEmpty()) {
1891 qCWarning(CUTELYST_SERVER) <<
"Can not load config from empty config file name";
1892 loadingConfig =
false;
1896 if (configLoaded.contains(fileToLoad.first)) {
1897 loadingConfig =
false;
1901 configLoaded.append(fileToLoad.first);
1903 QVariantMap loadedConfig;
1904 switch (fileToLoad.second) {
1905 case ConfigFormat::Ini:
1906 qCInfo(CUTELYST_SERVER) <<
"Loading INI configuratin:" << fileToLoad.first;
1909 case ConfigFormat::Json:
1910 qCInfo(CUTELYST_SERVER) <<
"Loading JSON configuration:" << fileToLoad.first;
1915 auto loadedIt = loadedConfig.cbegin();
1916 while (loadedIt != loadedConfig.cend()) {
1917 if (config.contains(loadedIt.key())) {
1918 QVariantMap currentMap = config.value(loadedIt.key()).toMap();
1919 const QVariantMap loadedMap = loadedIt.value().toMap();
1920 auto loadedMapIt = loadedMap.cbegin();
1921 while (loadedMapIt != loadedMap.cend()) {
1922 currentMap.insert(loadedMapIt.key(), loadedMapIt.value());
1925 config.insert(loadedIt.key(), currentMap);
1927 config.insert(loadedIt.key(), loadedIt.value());
1932 QVariantMap sessionConfig = loadedConfig.value(u
"server"_qs).toMap();
1934 applyConfig(sessionConfig);
1936 opt.insert(sessionConfig);
1938 loadingConfig =
false;
1940 if (!configToLoad.empty()) {
1945 void ServerPrivate::applyConfig(
const QVariantMap &config)
1949 auto it = config.constBegin();
1950 while (it != config.constEnd()) {
1962 if (prop.
userType() == value.userType()) {
1965 prop.
write(q, currentValues + value.toStringList());
1967 prop.
write(q, value);
1973 prop.
write(q, value);
1980 Protocol *ServerPrivate::getHttpProto()
2002 Protocol *ServerPrivate::getFastCgiProto()
2011 #include "moc_server.cpp" 2012 #include "moc_server_p.cpp" QFuture< ArgsType< Signal >> connect(Sender *sender, Signal signal)
void setConfig(const QVariantMap &config)
int exec(Cutelyst::Application *app=nullptr)
void moveToThread(QThread *targetThread)
QCommandLineOption addVersionOption()
virtual bool init() override
QThread * thread() const const
void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
static QVariantMap loadIniConfig(const QString &filename)
void addLibraryPath(const QString &path)
QVariantMap config() const noexcept
void start(QThread::Priority priority)
QString number(int n, int base)
void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
QStringList values(const QString &optionName) const const
int toInt(bool *ok, int base) const const
bool isEmpty() const const
bool start(Cutelyst::Application *app=nullptr)
const char * constData() const const
QByteArray number(int n, int base)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QCommandLineOption addHelpOption()
bool setCurrent(const QString &path)
void setApplicationDescription(const QString &description)
static QVariantMap loadJsonConfig(const QString &filename)
The Cutelyst namespace holds all public Cutelyst API.
void errorOccured(const QString &error)
bool isSet(const QString &name) const const
void parseCommandLine(const QStringList &args)
void setParent(QObject *parent)
void process(const QStringList &arguments)
QString & replace(qsizetype position, qsizetype n, QChar after)
QString fromLatin1(QByteArrayView str)
QByteArray toLatin1() const const
QStringList toStringList() const const
void showHelp(int exitCode)
QThread * currentThread()
bool addOption(const QCommandLineOption &option)
The Cutelyst application.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int compare(const QString &other, Qt::CaseSensitivity cs) const const
bool removeOne(const AT &t)
QString value(const QString &optionName) const const
qlonglong toLongLong(bool *ok, int base) const const
QString applicationName()
uint toUInt(bool *ok, int base) const const
Server(QObject *parent=nullptr)