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;
38using namespace Qt::StringLiterals;
39
40QByteArray dateHeader();
41
42ServerEngine::ServerEngine(Application *localApp,
43 int workerCore,
44 const QVariantMap &opts,
45 Server *server)
46 : Engine(localApp, workerCore, opts)
47 , m_lastDate{dateHeader()}
48 , m_server(server)
49{
50 m_lastDateTimer.start();
51
52 if (m_server->socketTimeout()) {
53 m_socketTimeout = new QTimer(this);
54 m_socketTimeout->setObjectName(u"Cutelyst::socketTimeout"_s);
55 m_socketTimeout->setInterval(std::chrono::seconds{m_server->socketTimeout()});
56 }
57
58 connect(this, &ServerEngine::shutdown, app(), [this] { Q_EMIT app()->shuttingDown(app()); });
59
60 const QStringList staticMap = m_server->staticMap();
61 const QStringList staticMap2 = m_server->staticMap2();
62 if (!staticMap.isEmpty() || !staticMap2.isEmpty()) {
63 // NOLINTNEXTLINE
64 auto staticMapPlugin = new StaticMap(app());
65
66 for (const QString &part : staticMap) {
67 staticMapPlugin->addStaticMap(
68 part.section(u'=', 0, 0), part.section(u'=', 1, 1), false);
69 }
70
71 for (const QString &part : staticMap2) {
72 staticMapPlugin->addStaticMap(part.section(u'=', 0, 0), part.section(u'=', 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 *cloneServer = balancer->createServer(this);
95 if (cloneServer) {
96 ++m_runningServers;
97 if (m_socketTimeout) {
98 connect(m_socketTimeout,
100 cloneServer,
101 &TcpServer::timeoutConnections);
102 }
103
104 if (cloneServer->protocol()->type() == Protocol::Type::Http11) {
105 cloneServer->setProtocol(getProtoHttp());
106 } else if (cloneServer->protocol()->type() == Protocol::Type::Http2) {
107 cloneServer->setProtocol(getProtoHttp2());
108 } else if (cloneServer->protocol()->type() == Protocol::Type::FastCGI1) {
109 cloneServer->setProtocol(getProtoFastCgi());
110 }
111
112#ifndef QT_NO_SSL
113 if (m_server->httpsH2()) {
114 auto sslServer = qobject_cast<TcpSslServer *>(cloneServer);
115 if (sslServer) {
116 sslServer->setHttp2Protocol(getProtoHttp2());
117 }
118 }
119#endif // QT_NO_SSL
120 }
121 }
122
123 const auto localServer = qobject_cast<LocalServer *>(server);
124 if (localServer) {
125 LocalServer *cloneServer = localServer->createServer(this);
126 if (cloneServer) {
127 ++m_runningServers;
128 if (m_socketTimeout) {
129 connect(m_socketTimeout,
131 cloneServer,
132 &LocalServer::timeoutConnections);
133 }
134
135 if (cloneServer->protocol()->type() == Protocol::Type::Http11) {
136 cloneServer->setProtocol(getProtoHttp());
137 } else if (cloneServer->protocol()->type() == Protocol::Type::Http2) {
138 cloneServer->setProtocol(getProtoHttp2());
139 } else if (cloneServer->protocol()->type() == Protocol::Type::FastCGI1) {
140 cloneServer->setProtocol(getProtoFastCgi());
141 }
142 }
143 }
144 }
145}
146
147void ServerEngine::postFork(int workerId)
148{
149 m_workerId = workerId;
150
151#ifdef Q_OS_UNIX
152 UnixFork::setSched(m_server, workerId, workerCore());
153#endif
154
155 if (Q_LIKELY(postForkApplication())) {
156 Q_EMIT started();
157 } else {
158 std::cerr << "Application failed to post fork, cheaping worker: " << workerId
159 << ", core: " << workerCore() << '\n';
160 Q_EMIT shutdown();
161 }
162}
163
164QByteArray ServerEngine::dateHeader()
165{
166 QString ret;
167 ret = u"\r\nDate: " + QLocale::c().toString(QDateTime::currentDateTimeUtc(),
168 u"ddd, dd MMM yyyy hh:mm:ss 'GMT"_s);
169 return ret.toLatin1();
170}
171
172Protocol *ServerEngine::getProtoHttp()
173{
174 if (!m_protoHttp) {
175 if (m_server->upgradeH2c()) {
176 m_protoHttp = new ProtocolHttp(m_server, getProtoHttp2());
177 } else {
178 m_protoHttp = new ProtocolHttp(m_server);
179 }
180 }
181 return m_protoHttp;
182}
183
184ProtocolHttp2 *ServerEngine::getProtoHttp2()
185{
186 if (!m_protoHttp2) {
187 m_protoHttp2 = new ProtocolHttp2(m_server);
188 }
189 return m_protoHttp2;
190}
191
192Protocol *ServerEngine::getProtoFastCgi()
193{
194 if (!m_protoFcgi) {
195 m_protoFcgi = new ProtocolFastCGI(m_server);
196 }
197 return m_protoFcgi;
198}
199
201{
202 if (Q_LIKELY(initApplication())) {
203 return true;
204 }
205
206 return false;
207}
208
209void ServerEngine::handleSocketShutdown(Socket *socket)
210{
211 if (socket->processing == 0) {
212 socket->connectionClose();
213 } else if (socket->proto->type() == Protocol::Type::Http11Websocket) {
214 auto req = static_cast<ProtoRequestHttp *>(socket->protoData);
215 req->webSocketClose(Response::CloseCode::CloseCodeGoingAway, {});
216 } else {
217 socket->protoData->headerConnection = ProtocolData::HeaderConnection::Close;
218 }
219}
220
221#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()