cutelyst 4.3.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 auto staticMapPlugin = new StaticMap(app());
63
64 for (const QString &part : staticMap) {
65 staticMapPlugin->addStaticMap(
66 part.section(QLatin1Char('='), 0, 0), part.section(QLatin1Char('='), 1, 1), false);
67 }
68
69 for (const QString &part : staticMap2) {
70 staticMapPlugin->addStaticMap(
71 part.section(QLatin1Char('='), 0, 0), part.section(QLatin1Char('='), 1, 1), true);
72 }
73 }
74}
75
76ServerEngine::~ServerEngine()
77{
78 delete m_protoFcgi;
79 delete m_protoHttp;
80 delete m_protoHttp2;
81}
82
84{
85 return m_workerId;
86}
87
88void ServerEngine::setServers(const std::vector<QObject *> &servers)
89{
90 for (QObject *server : servers) {
91 auto balancer = qobject_cast<TcpServerBalancer *>(server);
92 if (balancer) {
93 TcpServer *server = balancer->createServer(this);
94 if (server) {
95 ++m_runningServers;
96 if (m_socketTimeout) {
97 connect(
98 m_socketTimeout, &QTimer::timeout, server, &TcpServer::timeoutConnections);
99 }
100
101 if (server->protocol()->type() == Protocol::Type::Http11) {
102 server->setProtocol(getProtoHttp());
103 } else if (server->protocol()->type() == Protocol::Type::Http2) {
104 server->setProtocol(getProtoHttp2());
105 } else if (server->protocol()->type() == Protocol::Type::FastCGI1) {
106 server->setProtocol(getProtoFastCgi());
107 }
108
109#ifndef QT_NO_SSL
110 if (m_wsgi->httpsH2()) {
111 auto sslServer = qobject_cast<TcpSslServer *>(server);
112 if (sslServer) {
113 sslServer->setHttp2Protocol(getProtoHttp2());
114 }
115 }
116#endif // QT_NO_SSL
117 }
118 }
119
120 auto localServer = qobject_cast<LocalServer *>(server);
121 if (localServer) {
122 LocalServer *server = localServer->createServer(this);
123 if (server) {
124 ++m_runningServers;
125 if (m_socketTimeout) {
126 connect(m_socketTimeout,
128 server,
129 &LocalServer::timeoutConnections);
130 }
131
132 if (server->protocol()->type() == Protocol::Type::Http11) {
133 server->setProtocol(getProtoHttp());
134 } else if (server->protocol()->type() == Protocol::Type::Http2) {
135 server->setProtocol(getProtoHttp2());
136 } else if (server->protocol()->type() == Protocol::Type::FastCGI1) {
137 server->setProtocol(getProtoFastCgi());
138 }
139 }
140 }
141 }
142}
143
144void ServerEngine::postFork(int workerId)
145{
146 m_workerId = workerId;
147
148#ifdef Q_OS_UNIX
149 UnixFork::setSched(m_wsgi, workerId, workerCore());
150#endif
151
152 if (Q_LIKELY(postForkApplication())) {
153 Q_EMIT started();
154 } else {
155 std::cerr << "Application failed to post fork, cheaping worker: " << workerId
156 << ", core: " << workerCore() << std::endl;
157 Q_EMIT shutdown();
158 }
159}
160
161QByteArray ServerEngine::dateHeader()
162{
163 QString ret;
164 ret = QLatin1String("\r\nDate: ") +
166 QStringLiteral("ddd, dd MMM yyyy hh:mm:ss 'GMT"));
167 return ret.toLatin1();
168}
169
170Protocol *ServerEngine::getProtoHttp()
171{
172 if (!m_protoHttp) {
173 if (m_wsgi->upgradeH2c()) {
174 m_protoHttp = new ProtocolHttp(m_wsgi, getProtoHttp2());
175 } else {
176 m_protoHttp = new ProtocolHttp(m_wsgi);
177 }
178 }
179 return m_protoHttp;
180}
181
182ProtocolHttp2 *ServerEngine::getProtoHttp2()
183{
184 if (!m_protoHttp2) {
185 m_protoHttp2 = new ProtocolHttp2(m_wsgi);
186 }
187 return m_protoHttp2;
188}
189
190Protocol *ServerEngine::getProtoFastCgi()
191{
192 if (!m_protoFcgi) {
193 m_protoFcgi = new ProtocolFastCGI(m_wsgi);
194 }
195 return m_protoFcgi;
196}
197
199{
200 if (Q_LIKELY(initApplication())) {
201 return true;
202 }
203
204 return false;
205}
206
207void ServerEngine::handleSocketShutdown(Socket *socket)
208{
209 if (socket->processing == 0) {
210 socket->connectionClose();
211 } else if (socket->proto->type() == Protocol::Type::Http11Websocket) {
212 auto req = static_cast<ProtoRequestHttp *>(socket->protoData);
213 req->webSocketClose(Response::CloseCode::CloseCodeGoingAway, {});
214 } else {
215 socket->protoData->headerConnection = ProtocolData::HeaderConnection::Close;
216 }
217}
218
219#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()