cutelyst 5.0.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
serverengine.cpp
1/*
2 * SPDX-FileCopyrightText: (C) 2016-2022 Daniel Nicoletti <dantti12@gmail.com>
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5#include "serverengine.h"
6
7#include "config.h"
8#include "localserver.h"
9#include "protocol.h"
10#include "protocolfastcgi.h"
11#include "protocolhttp.h"
12#include "protocolhttp2.h"
13#include "protocolwebsocket.h"
14#include "server.h"
15#include "socket.h"
16#include "staticmap.h"
17#include "tcpserver.h"
18#include "tcpserverbalancer.h"
19#include "tcpsslserver.h"
20
21#ifdef Q_OS_UNIX
22# include "unixfork.h"
23#endif
24
25#include <Cutelyst/Application>
26#include <Cutelyst/Context>
27#include <Cutelyst/Request>
28#include <Cutelyst/Response>
29#include <iostream>
30#include <typeinfo>
31
32#include <QCoreApplication>
33#include <QLoggingCategory>
34
35Q_LOGGING_CATEGORY(C_SERVER_ENGINE, "cutelyst.server.engine", QtWarningMsg)
36
37using namespace Cutelyst;
38
39QByteArray dateHeader();
40
41ServerEngine::ServerEngine(Application *localApp,
42 int workerCore,
43 const QVariantMap &opts,
44 Server *wsgi)
45 : Engine(localApp, workerCore, opts)
46 , m_wsgi(wsgi)
47{
48 m_lastDate = dateHeader();
49 m_lastDateTimer.start();
50
51 if (m_wsgi->socketTimeout()) {
52 m_socketTimeout = new QTimer(this);
53 m_socketTimeout->setObjectName(QStringLiteral("Cutelyst::socketTimeout"));
54 m_socketTimeout->setInterval(std::chrono::seconds{m_wsgi->socketTimeout()});
55 }
56
57 connect(this, &ServerEngine::shutdown, app(), [this] { Q_EMIT app()->shuttingDown(app()); });
58
59 const QStringList staticMap = m_wsgi->staticMap();
60 const QStringList staticMap2 = m_wsgi->staticMap2();
61 if (!staticMap.isEmpty() || !staticMap2.isEmpty()) {
62 // NOLINTNEXTLINE
63 auto staticMapPlugin = new StaticMap(app());
64
65 for (const QString &part : staticMap) {
66 staticMapPlugin->addStaticMap(
67 part.section(QLatin1Char('='), 0, 0), part.section(QLatin1Char('='), 1, 1), false);
68 }
69
70 for (const QString &part : staticMap2) {
71 staticMapPlugin->addStaticMap(
72 part.section(QLatin1Char('='), 0, 0), part.section(QLatin1Char('='), 1, 1), true);
73 }
74 }
75}
76
77ServerEngine::~ServerEngine()
78{
79 delete m_protoFcgi;
80 delete m_protoHttp;
81 delete m_protoHttp2;
82}
83
85{
86 return m_workerId;
87}
88
89void ServerEngine::setServers(const std::vector<QObject *> &servers)
90{
91 for (QObject *server : servers) {
92 auto balancer = qobject_cast<TcpServerBalancer *>(server);
93 if (balancer) {
94 TcpServer *server = balancer->createServer(this);
95 if (server) {
96 ++m_runningServers;
97 if (m_socketTimeout) {
98 connect(
99 m_socketTimeout, &QTimer::timeout, server, &TcpServer::timeoutConnections);
100 }
101
102 if (server->protocol()->type() == Protocol::Type::Http11) {
103 server->setProtocol(getProtoHttp());
104 } else if (server->protocol()->type() == Protocol::Type::Http2) {
105 server->setProtocol(getProtoHttp2());
106 } else if (server->protocol()->type() == Protocol::Type::FastCGI1) {
107 server->setProtocol(getProtoFastCgi());
108 }
109
110#ifndef QT_NO_SSL
111 if (m_wsgi->httpsH2()) {
112 auto sslServer = qobject_cast<TcpSslServer *>(server);
113 if (sslServer) {
114 sslServer->setHttp2Protocol(getProtoHttp2());
115 }
116 }
117#endif // QT_NO_SSL
118 }
119 }
120
121 auto localServer = qobject_cast<LocalServer *>(server);
122 if (localServer) {
123 LocalServer *server = localServer->createServer(this);
124 if (server) {
125 ++m_runningServers;
126 if (m_socketTimeout) {
127 connect(m_socketTimeout,
129 server,
130 &LocalServer::timeoutConnections);
131 }
132
133 if (server->protocol()->type() == Protocol::Type::Http11) {
134 server->setProtocol(getProtoHttp());
135 } else if (server->protocol()->type() == Protocol::Type::Http2) {
136 server->setProtocol(getProtoHttp2());
137 } else if (server->protocol()->type() == Protocol::Type::FastCGI1) {
138 server->setProtocol(getProtoFastCgi());
139 }
140 }
141 }
142 }
143}
144
145void ServerEngine::postFork(int workerId)
146{
147 m_workerId = workerId;
148
149#ifdef Q_OS_UNIX
150 UnixFork::setSched(m_wsgi, workerId, workerCore());
151#endif
152
153 if (Q_LIKELY(postForkApplication())) {
154 Q_EMIT started();
155 } else {
156 std::cerr << "Application failed to post fork, cheaping worker: " << workerId
157 << ", core: " << workerCore() << '\n';
158 Q_EMIT shutdown();
159 }
160}
161
162QByteArray ServerEngine::dateHeader()
163{
164 QString ret;
165 ret = QLatin1String("\r\nDate: ") +
167 QStringLiteral("ddd, dd MMM yyyy hh:mm:ss 'GMT"));
168 return ret.toLatin1();
169}
170
171Protocol *ServerEngine::getProtoHttp()
172{
173 if (!m_protoHttp) {
174 if (m_wsgi->upgradeH2c()) {
175 m_protoHttp = new ProtocolHttp(m_wsgi, getProtoHttp2());
176 } else {
177 m_protoHttp = new ProtocolHttp(m_wsgi);
178 }
179 }
180 return m_protoHttp;
181}
182
183ProtocolHttp2 *ServerEngine::getProtoHttp2()
184{
185 if (!m_protoHttp2) {
186 m_protoHttp2 = new ProtocolHttp2(m_wsgi);
187 }
188 return m_protoHttp2;
189}
190
191Protocol *ServerEngine::getProtoFastCgi()
192{
193 if (!m_protoFcgi) {
194 m_protoFcgi = new ProtocolFastCGI(m_wsgi);
195 }
196 return m_protoFcgi;
197}
198
200{
201 if (Q_LIKELY(initApplication())) {
202 return true;
203 }
204
205 return false;
206}
207
208void ServerEngine::handleSocketShutdown(Socket *socket)
209{
210 if (socket->processing == 0) {
211 socket->connectionClose();
212 } else if (socket->proto->type() == Protocol::Type::Http11Websocket) {
213 auto req = static_cast<ProtoRequestHttp *>(socket->protoData);
214 req->webSocketClose(Response::CloseCode::CloseCodeGoingAway, {});
215 } else {
216 socket->protoData->headerConnection = ProtocolData::HeaderConnection::Close;
217 }
218}
219
220#include "moc_serverengine.cpp"
The Cutelyst application.
Definition application.h:66
The Cutelyst Engine.
Definition engine.h:20
bool initApplication()
Definition engine.cpp:73
int workerCore() const
Definition engine.cpp:67
bool postForkApplication()
Definition engine.cpp:90
virtual int workerId() const override
virtual bool init() override
Implements a web server.
Definition server.h:60
The Cutelyst namespace holds all public Cutelyst API.
QDateTime currentDateTimeUtc()
bool isEmpty() const const
QLocale c()
QString toString(QDate date, QLocale::FormatType format) const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QByteArray toLatin1() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void timeout()