ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
http_server.h
Go to the documentation of this file.
1
20#pragma once
21
22#include <atomic>
23#include <cstdint>
24#include <functional>
25#include <string>
26#include <thread>
27#include <unordered_map>
28#include <vector>
29
30#include "json.h"
31
32namespace ascii_query {
33
38 std::string method;
39 std::string path;
40 std::string query_string;
41 std::unordered_map<std::string, std::string> headers;
42 std::unordered_map<std::string, std::string> params;
43 std::string body;
44
51 [[nodiscard]] std::string param(const std::string &name, const std::string &default_value = "") const {
52 auto it = params.find(name);
53 return (it != params.end()) ? it->second : default_value;
54 }
55
61 [[nodiscard]] bool hasParam(const std::string &name) const {
62 return params.find(name) != params.end();
63 }
64
71 [[nodiscard]] int paramInt(const std::string &name, int default_value = 0) const {
72 auto it = params.find(name);
73 if (it == params.end())
74 return default_value;
75 try {
76 return std::stoi(it->second);
77 } catch (...) {
78 return default_value;
79 }
80 }
81
88 [[nodiscard]] std::string header(const std::string &name, const std::string &default_value = "") const;
89};
90
95 int status_code = 200;
96 std::string status_text = "OK";
97 std::unordered_map<std::string, std::string> headers;
98 std::string body;
99
100 HttpResponse() = default;
101 HttpResponse(int code, std::string text, std::string content_type, std::string response_body)
102 : status_code(code), status_text(std::move(text)), body(std::move(response_body)) {
103 headers["Content-Type"] = std::move(content_type);
104 }
105
106 // Convenience constructors
107 static HttpResponse ok(const std::string &content_type, const std::string &body) {
108 return HttpResponse(200, "OK", content_type, body);
109 }
110
111 static HttpResponse json(const std::string &body) {
112 return ok("application/json", body);
113 }
114
115 static HttpResponse html(const std::string &body) {
116 return ok("text/html; charset=utf-8", body);
117 }
118
119 static HttpResponse text(const std::string &body) {
120 return ok("text/plain", body);
121 }
122
123 static HttpResponse notFound(const std::string &message = "Not Found") {
124 return HttpResponse(404, "Not Found", "application/json", R"({"error":")" + json::escape(message) + R"("})");
125 }
126
127 static HttpResponse badRequest(const std::string &message = "Bad Request") {
128 return HttpResponse(400, "Bad Request", "application/json", R"({"error":")" + json::escape(message) + R"("})");
129 }
130
131 static HttpResponse serverError(const std::string &message = "Internal Server Error") {
132 return HttpResponse(500, "Internal Server Error", "application/json",
133 R"({"error":")" + json::escape(message) + R"("})");
134 }
135
137 return HttpResponse(204, "No Content", "text/plain", "");
138 }
139
143 HttpResponse &setHeader(const std::string &name, const std::string &value) {
144 headers[name] = value;
145 return *this;
146 }
147
151 [[nodiscard]] std::string serialize() const;
152};
153
157using RouteHandler = std::function<HttpResponse(const HttpRequest &)>;
158
163public:
164 HttpServer();
165 ~HttpServer();
166
167 // Non-copyable
168 HttpServer(const HttpServer &) = delete;
169 HttpServer &operator=(const HttpServer &) = delete;
170
177 void addRoute(const std::string &method, const std::string &path, RouteHandler handler);
178
183 void setDefaultHandler(RouteHandler handler);
184
190 bool start(uint16_t port);
191
195 void stop();
196
200 [[nodiscard]] bool isRunning() const {
201 return running_;
202 }
203
207 [[nodiscard]] uint16_t port() const {
208 return port_;
209 }
210
214 [[nodiscard]] const std::string &lastError() const {
215 return last_error_;
216 }
217
224 bool processOneRequest();
225
226private:
227 struct Route {
228 std::string method;
229 std::string path;
230 RouteHandler handler;
231 };
232
233 std::vector<Route> routes_;
234 RouteHandler default_handler_;
235
236 std::atomic<bool> running_{false};
237 std::thread server_thread_;
238 uint16_t port_ = 0;
239 int server_socket_ = -1;
240 std::string last_error_;
241
242 void serverLoop();
243 void handleClient(int client_socket);
244 bool parseRequest(const std::string &raw, HttpRequest &request);
245 void parseQueryString(const std::string &query, std::unordered_map<std::string, std::string> &params);
246 std::string urlDecode(const std::string &str);
247 RouteHandler findHandler(const std::string &method, const std::string &path);
248};
249
250} // namespace ascii_query
Simple single-threaded HTTP server.
uint16_t port() const
Get the port the server is listening on.
void addRoute(const std::string &method, const std::string &path, RouteHandler handler)
Add a route handler.
void setDefaultHandler(RouteHandler handler)
Set a default handler for unmatched routes.
HttpServer(const HttpServer &)=delete
bool processOneRequest()
Process one request (blocking)
HttpServer & operator=(const HttpServer &)=delete
bool start(uint16_t port)
Start the server.
const std::string & lastError() const
Get the last error message.
void stop()
Stop the server.
bool isRunning() const
Check if server is running.
unsigned short uint16_t
Definition common.h:57
Minimal JSON serialization helpers (header-only)
std::string escape(const std::string &str)
Escape a string for JSON output.
Definition json.h:30
std::function< HttpResponse(const HttpRequest &)> RouteHandler
Route handler function type.
Parsed HTTP request.
Definition http_server.h:37
std::unordered_map< std::string, std::string > params
Parsed query parameters.
Definition http_server.h:42
std::string query_string
Query string (after ?)
Definition http_server.h:40
int paramInt(const std::string &name, int default_value=0) const
Get a query parameter as integer.
Definition http_server.h:71
std::string path
Request path (without query string)
Definition http_server.h:39
std::unordered_map< std::string, std::string > headers
Request headers.
Definition http_server.h:41
std::string body
Request body.
Definition http_server.h:43
std::string param(const std::string &name, const std::string &default_value="") const
Get a query parameter value.
Definition http_server.h:51
std::string header(const std::string &name, const std::string &default_value="") const
Get a header value.
std::string method
GET, POST, etc.
Definition http_server.h:38
bool hasParam(const std::string &name) const
Check if a query parameter exists (flag-style, like &break)
Definition http_server.h:61
HTTP response builder.
Definition http_server.h:94
std::unordered_map< std::string, std::string > headers
Definition http_server.h:97
static HttpResponse text(const std::string &body)
HttpResponse & setHeader(const std::string &name, const std::string &value)
Set a header.
std::string serialize() const
Serialize response to HTTP/1.1 format.
static HttpResponse json(const std::string &body)
static HttpResponse noContent()
HttpResponse(int code, std::string text, std::string content_type, std::string response_body)
static HttpResponse ok(const std::string &content_type, const std::string &body)
static HttpResponse html(const std::string &body)
static HttpResponse notFound(const std::string &message="Not Found")
static HttpResponse serverError(const std::string &message="Internal Server Error")
static HttpResponse badRequest(const std::string &message="Bad Request")