UniSet @VERSION@
JHttpServer.h
1/*
2 * Copyright (c) 2025 Pavel Vainerman.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation, version 2.1.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Lesser Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16// --------------------------------------------------------------------------
17#ifndef JHttpServer_H_
18#define JHttpServer_H_
19// --------------------------------------------------------------------------
20#include <memory>
21#include <atomic>
22#include <condition_variable>
23#include <future>
24#include <mutex>
25#include <queue>
26#include <Poco/Net/HTTPServer.h>
27#include <Poco/Net/HTTPRequestHandler.h>
28#include <Poco/Net/HTTPServerRequest.h>
29#include <Poco/Net/HTTPServerResponse.h>
30#include <Poco/Net/HTTPRequestHandlerFactory.h>
31#include "DebugStream.h"
32// --------------------------------------------------------------------------
33namespace uniset
34{
35 // ----------------------------------------------------------------------
36 class JHttpServer final:
37 public std::enable_shared_from_this<JHttpServer>,
38 public Poco::Net::HTTPRequestHandlerFactory
39 {
40 public:
41 JHttpServer( size_t httpMaxThreads, size_t httpMaxRequestQueue );
42 ~JHttpServer() final;
43
44 bool isRunning();
45 void start( const std::string& host, int port );
46 void stop();
47 void softStop(std::chrono::milliseconds timeout);
48
49 void setProcessTimeout(std::chrono::milliseconds d) noexcept
50 {
51 processTimeout_ = d;
52 }
53 std::chrono::milliseconds processTimeout() const noexcept
54 {
55 return processTimeout_;
56 }
57
58 inline std::shared_ptr<DebugStream> log() noexcept
59 {
60 return mylog;
61 }
62
63 class Factory : public HTTPRequestHandlerFactory
64 {
65 public:
66 Factory( JHttpServer* s ): srv(s) {}
67
68 Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& req) override
69 {
70 return srv->createRequestHandler(req);
71 }
72 private:
73 JHttpServer* srv;
74 };
75
77 {
78 std::string method;
79 std::string uri;
80 std::string version;
81 std::vector<std::pair<std::string, std::string>> headers;
82 std::string body;
83 };
84
86 {
87 int status = 200;
88 std::string reason = "OK";
89 std::vector<std::pair<std::string, std::string>> headers;
90 std::string body;
91 };
92
94 {
96 bool finished = false;
97 };
98
99 using HandlerFn = std::function<ResponseSnapshot(const RequestSnapshot&)>;
100
101 void httpLoop( HandlerFn& fn, size_t count, std::chrono::milliseconds& timeout );
102
103 void setMaxQueueSize(size_t n) noexcept
104 {
105 queue_.setMaxSize(n);
106 }
107
108 class Handler;
110 {
111 public:
112 struct Job
113 {
114 RequestSnapshot req;
115 std::promise<ResponseSnapshot> prom;
116 std::shared_ptr<std::atomic<bool>> cancelled = std::make_shared<std::atomic<bool>>(false);
117 };
118
119 bool push(Job&& j)
120 {
121 {
122 std::lock_guard<std::mutex> lk(m_);
123
124 if (maxSize_ > 0 && q_.size() >= maxSize_) return false;
125
126 q_.emplace(std::move(j));
127 }
128 cv_.notify_one();
129 return true;
130 }
131
132 // returns false when shutting down and queue is empty
133 bool pop(Job& out, std::chrono::milliseconds timeout)
134 {
135 std::unique_lock<std::mutex> lk(m_);
136
137 bool ret = cv_.wait_for(lk, timeout, [&]
138 {
139 return stop_ || !q_.empty();
140 });
141
142 if( !ret )
143 return false;
144
145 if(stop_ && q_.empty())
146 return false;
147
148 out = std::move(q_.front());
149 q_.pop();
150 return true;
151 }
152
153
154 bool empty() const
155 {
156 std::lock_guard<std::mutex> lk(m_);
157 return q_.empty();
158 }
159
160 void setMaxSize(size_t n) noexcept
161 {
162 maxSize_ = n;
163 }
164
165 void shutdown()
166 {
167 {
168 std::lock_guard<std::mutex> lk(m_);
169 stop_ = true;
170 }
171 cv_.notify_all();
172 }
173
174 void clear(int status, const std::string& reason, const std::string& body)
175 {
176 std::lock_guard<std::mutex> lk(m_);
177
178 while (!q_.empty())
179 {
180 auto& job = q_.front();
181 ResponseSnapshot resp;
182 resp.status = status;
183 resp.reason = reason;
184 resp.headers = { {"Content-Type", "text/plain"} };
185 resp.body = body;
186
187 try
188 {
189 job.prom.set_value(std::move(resp));
190 }
191 catch (...) {}
192
193 q_.pop();
194 }
195 }
196
197 void reset()
198 {
199 std::lock_guard<std::mutex> lk(m_);
200 stop_ = false;
201 }
202
203 private:
204 mutable std::mutex m_;
205 std::condition_variable cv_;
206 std::queue<Job> q_;
207 bool stop_ = false;
208 size_t maxSize_ = 0;
209 };
210
211 protected:
212 friend class Factory;
213 Poco::Net::HTTPRequestHandler* createRequestHandler( const Poco::Net::HTTPServerRequest& ) override;
214
215 private:
216 Poco::Net::SocketAddress sa;
217 std::shared_ptr<Poco::Net::HTTPServer> http;
218 std::shared_ptr<DebugStream> mylog;
219 std::atomic_bool started;
220
221 // default timeout: 10s
222 std::chrono::milliseconds processTimeout_{std::chrono::seconds(10)};
223
224 // lifecycle
225 std::atomic_bool workerRunning_{false};
226 std::atomic_bool softStopping_{false};
227 std::atomic_bool workerBusy_{false};
228 std::condition_variable cvStop_;
229 std::mutex cvStopMutex_;
230
231 size_t httpMaxThreads = { 3 };
232 size_t httpMaxRequestQueue = { 50 };
233
234 // request funnel
235 RequestQueue queue_;
236
237 };
238 // ----------------------------------------------------------------------
239} // end of namespace uniset
240// --------------------------------------------------------------------------
241#endif
Definition JHttpServer.h:64
Definition JHttpServer.h:110
Definition JHttpServer.h:39
Definition AccessConfig.h:30
Definition JHttpServer.h:113
Definition JHttpServer.h:77
Definition JHttpServer.h:94
Definition JHttpServer.h:86