WebFramework v3.0.12
Web framework for C++.
Loading...
Searching...
No Matches
ThreadPoolWebServer.cpp
1#include "ThreadPoolWebServer.h"
2
3#include "Log.h"
4
5#include "Exceptions/FileDoesNotExistException.h"
6#include "Exceptions/NotFoundException.h"
7#include "Exceptions/SSLException.h"
8#include "Utility/Singletons/HTTPSSingleton.h"
9#include "HTTPSNetwork.h"
10
11using namespace std;
12
13namespace framework
14{
15 ThreadPoolWebServer::Client::Client(SSL* ssl, SSL_CTX* context, SOCKET clientSocket, sockaddr address, function<void()>&& cleanup) :
16 stream
17 (
18 ssl ?
19 make_unique<web::HTTPSNetwork>(clientSocket, ssl, context) :
20 make_unique<web::HTTPNetwork>(clientSocket)
21 ),
22 cleanup(move(cleanup)),
23 address(address),
24 ssl(ssl),
25 context(context),
26 clientSocket(clientSocket),
27 isBusy(false),
28 webExceptionAcquired(false)
29 {
30
31 }
32
33 bool ThreadPoolWebServer::Client::serve
34 (
35 SessionsManager& sessionsManager,
36 web::BaseTCPServer& server,
37 interfaces::IStaticFile& staticResources,
38 interfaces::IDynamicFile& dynamicResources,
39 sqlite::SQLiteManager& databaseManager,
40 ExecutorsManager& executorsManager,
41 ResourceExecutor& resourceExecutor,
42 threading::ThreadPool& threadPool
43 )
44 {
45 if (stream.eof() || webExceptionAcquired)
46 {
47 return true;
48 }
49
50 if (isBusy)
51 {
52 return false;
53 }
54
55 try
56 {
57 HTTPRequest request(sessionsManager, server, staticResources, dynamicResources, databaseManager, address, stream);
58 HTTPResponse response;
59
60 stream >> request;
61
62 if (stream.eof())
63 {
64 return true;
65 }
66
67 optional<function<void(HTTPRequest&, HTTPResponse&)>> threadPoolFunction = executorsManager.service(request, response, statefulExecutors);
68
69 if (threadPoolFunction)
70 {
71 isBusy = true;
72
73 threadPool.addTask
74 (
75 [this, &resourceExecutor, request = move(request), response = move(response), threadPoolFunction = move(threadPoolFunction)]() mutable
76 {
77 try
78 {
79 (*threadPoolFunction)(request, response);
80
81 if (response)
82 {
83 stream << response;
84 }
85 }
86 catch (const web::exceptions::WebException& e)
87 {
88 if (Log::isValid())
89 {
90 Log::error("Thread pool serve exception: {}", "ThreadPool", e.what());
91 }
92
93 webExceptionAcquired = true;
94 }
95 catch (const exceptions::BadRequestException& e) // 400
96 {
97 resourceExecutor.badRequestError(response, &e);
98
99 stream << response;
100 }
101 catch (const file_manager::exceptions::FileDoesNotExistException& e) // 404
102 {
103 resourceExecutor.notFoundError(response, &e);
104
105 stream << response;
106 }
107 catch (const exceptions::NotFoundException& e) // 404
108 {
109 resourceExecutor.notFoundError(response, &e);
110
111 stream << response;
112 }
113 catch (const exceptions::BaseExecutorException& e) // 500
114 {
115 resourceExecutor.internalServerError(response, &e);
116
117 stream << response;
118 }
119 catch (const exception& e)
120 {
121 resourceExecutor.internalServerError(response, &e);
122
123 stream << response;
124 }
125 catch (...) // 500
126 {
127 resourceExecutor.internalServerError(response, nullptr);
128
129 stream << response;
130 }
131 },
132 [this]() mutable
133 {
134 isBusy = false;
135 }
136 );
137
138 return false;
139 }
140 else if (response)
141 {
142 stream << response;
143 }
144 }
145 catch (const web::exceptions::WebException& e)
146 {
147 if (Log::isValid())
148 {
149 Log::error("Serve exception: {}", "ThreadPool", e.what());
150 }
151
152 return true;
153 }
154 catch (const exceptions::BadRequestException& e) // 400
155 {
156 HTTPResponse response;
157
158 resourceExecutor.badRequestError(response, &e);
159
160 stream << response;
161 }
162 catch (const file_manager::exceptions::FileDoesNotExistException& e) // 404
163 {
164 HTTPResponse response;
165
166 resourceExecutor.notFoundError(response, &e);
167
168 stream << response;
169 }
170 catch (const exceptions::NotFoundException& e) // 404
171 {
172 HTTPResponse response;
173
174 resourceExecutor.notFoundError(response, &e);
175
176 stream << response;
177 }
178 catch (const exceptions::BaseExecutorException& e) // 500
179 {
180 HTTPResponse response;
181
182 resourceExecutor.internalServerError(response, &e);
183
184 stream << response;
185 }
186 catch (const exception& e)
187 {
188 HTTPResponse response;
189
190 resourceExecutor.internalServerError(response, &e);
191
192 stream << response;
193 }
194 catch (...) // 500
195 {
196 HTTPResponse response;
197
198 resourceExecutor.internalServerError(response, nullptr);
199
200 stream << response;
201 }
202
203 return stream.eof();
204 }
205
206 ThreadPoolWebServer::Client::~Client()
207 {
208 if (cleanup)
209 {
210 cleanup();
211 }
212 }
213
214 void ThreadPoolWebServer::serveClients()
215 {
216 for (size_t i = 0; i < clients.size();)
217 {
218 Client* client = clients[i];
219
220 bool finished = client->serve
221 (
222 sessionsManager,
223 *this,
224 *resources,
225 *resources,
226 databaseManager,
227 executorsManager,
228 *resources,
229 threadPool
230 );
231
232 if (finished)
233 {
234 delete client;
235
236 clients.erase(clients.begin() + i);
237
238 if (i)
239 {
240 i--;
241 }
242 }
243 else
244 {
245 i++;
246 }
247 }
248 }
249
250 void ThreadPoolWebServer::clientConnection(const string& ip, SOCKET clientSocket, sockaddr address, function<void()>& cleanup) //-V688
251 {
252 SSL* ssl = nullptr;
253
254 try
255 {
256 if (useHTTPS)
257 {
258 ssl = SSL_new(context);
259
260 if (!ssl)
261 {
262 throw web::exceptions::SSLException(__LINE__, __FILE__);
263 }
264
265 if (!SSL_set_fd(ssl, static_cast<int>(clientSocket)))
266 {
267 SSL_free(ssl);
268
269 throw web::exceptions::SSLException(__LINE__, __FILE__);
270 }
271
272 if (int errorCode = SSL_accept(ssl); errorCode != 1)
273 {
274 throw web::exceptions::SSLException(__LINE__, __FILE__, ssl, errorCode);
275 }
276 }
277
278 clients.push_back(new Client(ssl, context, clientSocket, address, move(cleanup)));
279 }
280 catch (const web::exceptions::SSLException& e)
281 {
282 if (Log::isValid())
283 {
284 Log::error("SSL exception: {}, ip: {}", "LogHTTPS", e.what(), ip);
285 }
286 }
287
288 this->serveClients();
289 }
290
291 void ThreadPoolWebServer::onInvalidConnectionReceive()
292 {
293 this->serveClients();
294 }
295
296 ThreadPoolWebServer::ThreadPoolWebServer
297 (
298 const json::JSONParser& configuration,
299 const vector<utility::JSONSettingsParser>& parsers,
300 const filesystem::path& assets,
301 const filesystem::path& pathToTemplates,
302 uint64_t cachingSize,
303 string_view ip,
304 string_view port,
305 DWORD timeout,
306 const vector<string>& pathToSources,
307 uint32_t threadCount
308 ) :
309 BaseTCPServer
310 (
311 port,
312 ip,
313 timeout,
314 false,
315 1,
316 false
317 ),
318 IExecutorFunctionality
319 (
320 configuration,
321 assets,
322 pathToTemplates,
323 cachingSize,
324 parsers,
325 pathToSources
326 ),
327 threadPool(threadCount ? threadCount : thread::hardware_concurrency())
328 {
329
330 }
331}