MLIB
Loading...
Searching...
No Matches
httpd.h
Go to the documentation of this file.
1/*
2 Copyright (c) Mircea Neacsu (2014-2025) Licensed under MIT License.
3 This is part of MLIB project. See LICENSE file for full license terms.
4*/
5
7#pragma once
8
9#include "tcpserver.h"
10#include <string>
11#include <map>
12#include <deque>
13#include <typeindex>
14#include <filesystem>
15
17#define HTTPD_MAX_HEADER 8192
18
21#define HTTP_OK 0
22#define HTTP_ERR_WRITE -1
23#define HTTP_ERR_FOPEN -2
24#define HTTP_ERR_FREAD -3
25#define HTTP_NO_HANDLER -4
27
28namespace mlib::http {
29
30class connection;
31
33struct ci_less : public std::function<bool (std::string, std::string)>
34{
35 bool operator() (const std::string& lhs, const std::string& rhs) const
36 {
37 return _stricmp (lhs.c_str (), rhs.c_str ()) < 0;
38 }
39};
40
43typedef std::map<std::string, std::string, ci_less> str_pairs;
44
46typedef std::function<int (connection& client, void* info)> uri_handler;
47
49class connection : public thread
50{
51 friend class server;
52
53public:
54
56 const std::string& get_path () const;
57
59 const std::string& get_method () const;
60
62 const std::string& get_query () const;
63
65 const std::string& get_body () const;
66
67 void add_ohdr (const std::string& hdr, const std::string& value);
68
70 bool has_ihdr (const std::string& hdr) const;
71
73 const std::string& get_ihdr (const std::string& hdr) const;
74
76 const str_pairs& get_request_headers () const;
77
79 bool has_ohdr (const std::string& hdr) const;
80
82 const std::string& get_ohdr (const std::string& hdr) const;
83
85 bool has_qparam (const std::string& key);
86
88 const std::string& get_qparam (const std::string& key);
89
91 bool has_bparam (const std::string& key);
92
94 const std::string& get_bparam (const std::string& key);
95
97 int get_content_length () const;
98 sockstream& out ();
99
100 void respond (unsigned int code, const std::string& reason = std::string());
101 void redirect (const std::string& uri, unsigned int code = 303);
102 void serve404 (const char* text = 0);
103 int serve_file (const std::filesystem::path& file);
104 int serve_shtml (const std::filesystem::path& file);
105 int serve_buffer (const BYTE* buffer, size_t sz);
106 int serve_buffer (const std::string& str);
107
108protected:
109 connection (sock& socket, server& server);
110
112 void run () override;
113 void term () override;
114
115 server& parent;
116 sockstream ws;
117
118private:
119 bool parse_request (const std::string& req);
120 bool parse_headers (const std::string& hdrs);
121 bool parse_body ();
122 void parse_query ();
123 void process_valid_request ();
124 void process_ssi (const char* request);
125 int do_auth ();
126 void serve401 (const char* realm);
127 bool should_close ();
128
129 std::string path_;
130 std::string query_;
131 std::string method_;
132 std::string http_version;
133 std::string body;
134 int content_len;
135 std::string part_boundary;
136 bool response_sent;
137 str_pairs oheaders;
138 str_pairs iheaders;
139 str_pairs qparams;
140 str_pairs bparams;
141 bool query_parsed, body_parsed;
142
143 struct user
144 {
145 std::string name;
146 std::string pwd;
147 };
148 std::multimap<std::string, user> auth; // authenticated users
149
150};
151
153class server : public tcpserver
154{
155public:
156 explicit server (unsigned short port = 0, unsigned int maxconn = 0);
157 ~server ();
158
159 void add_ohdr (const std::string& hdr, const std::string& value);
160 void remove_ohdr (const std::string& hdr);
161
163 void add_handler (const std::string& uri, uri_handler func, void* info = 0);
164 void add_post_handler (const std::string& uri, uri_handler func, void* info = 0);
165 bool add_user (const char* realm, const char* username, const char* pwd);
166 bool remove_user (const char* realm, const char* username);
167 void add_realm (const char* realm, const char* uri);
168
169 template <typename T>
170 void add_var (const std::string& name, const T* addr, const char* fmt = nullptr)
171 {
172 constexpr vtype t = std::is_same_v<T, bool> ? VT_BOOL
173 : std::is_same_v<T, char> ? VT_CHAR
174 : std::is_same_v<T, std::string> ? VT_STRING
175 : std::is_same_v<T, short> ? VT_SHORT
176 : std::is_same_v<T, unsigned short> ? VT_USHORT
177 : std::is_same_v<T, int> ? VT_INT
178 : std::is_same_v<T, unsigned int> ? VT_UINT
179 : std::is_same_v<T, long> ? VT_LONG
180 : std::is_same_v<T, unsigned long> ? VT_ULONG
181 : VT_UNKNOWN;
182 static_assert (t != VT_UNKNOWN);
183 add_var (name, t, addr, fmt);
184 }
185
186 template <typename T>
187 std::enable_if_t<std::is_floating_point_v<T>> add_var (const std::string& name, const T* addr,
188 const char* fmt = nullptr,
189 double multiplier = 1.)
190 {
191 constexpr vtype t = std::is_same_v<T, float> ? VT_FLOAT
192 : std::is_same_v<T, float> ? VT_DOUBLE
193 : VT_UNKNOWN;
194 static_assert (t != VT_UNKNOWN);
195 add_var (name, t, addr, fmt, multiplier);
196 }
197
198 const std::string get_var (const std::string& name);
199 void aquire_varlock ();
200 void release_varlock ();
201 bool try_varlock ();
202
203 void name (const char* nam);
204 void docroot (const std::string& path);
205 const std::filesystem::path& docroot () const;
206 void add_alias (const std::string& uri, const std::string& path);
207
208 void default_uri (const std::string& name)
209 {
210 defuri = name;
211 };
212 const std::string& default_uri ()
213 {
214 return defuri;
215 };
216
217 static void add_mime_type (const std::string& ext, const std::string& type, bool shtml = false);
218 static void delete_mime_type (const std::string& ext);
219
220 bool is_protected (const std::string& uri, std::string& realm);
221 bool authenticate (const std::string& realm, const std::string& user, const std::string& pwd);
222
223 friend class connection;
224
225protected:
242 int invoke_handler (connection& client);
243 int invoke_post_handler (connection& client);
244
245 bool find_alias (const std::string& res, std::filesystem::path& path);
246 const std::string& guess_mimetype (const std::filesystem::path& fn, bool& shtml);
248 void add_var (const std::string& name, vtype t, const void* addr, const char* fmt = nullptr,
249 double multiplier = 1.);
250
251private:
252 str_pairs out_headers;
253 mlib::criticalsection hdr_lock;
254 str_pairs realms;
255
256 struct handle_info
257 {
258 handle_info (uri_handler h_, void* info_);
259
260 uri_handler h;
261 void* nfo;
262 std::shared_ptr<mlib::criticalsection> in_use;
263 };
264 std::map<std::string, handle_info> handlers;
265 std::map<std::string, handle_info> post_handlers;
266
267 std::map<std::string, std::string> aliases;
268
269 struct var_info
270 {
271 std::string fmt;
272 vtype type;
273 const void* addr;
274 double multiplier;
275 };
276 std::map<std::string, var_info> variables;
277 mlib::criticalsection varlock;
278
279 struct user
280 {
281 std::string name;
282 std::string pwd;
283 };
284 std::multimap<std::string, user> credentials;
285
286 std::filesystem::path root;
287 std::string defuri;
288};
289
290/*==================== INLINE FUNCTIONS ===========================*/
291
304inline
305const std::string& connection::get_path () const
306{
307 return path_;
308};
309
319inline const std::string& connection::get_method () const
320{
321 return method_;
322};
323
338inline const std::string& connection::get_query () const
339{
340 return query_;
341};
342
346inline
347const std::string& connection::get_body () const
348{
349 return body;
350};
351
361inline
362void connection::add_ohdr (const std::string& hdr, const std::string& value)
363{
364 oheaders[hdr] = value;
365}
366
368inline
369bool connection::has_ihdr (const std::string& hdr) const
370{
371 return iheaders.find (hdr) != iheaders.end();
372}
373
381inline
382const std::string& connection::get_ihdr (const std::string& hdr) const
383{
384 return iheaders.at(hdr);
385}
386
391inline
392bool connection::has_ohdr (const std::string& hdr) const
393{
394 lock l (parent.hdr_lock);
395 return parent.out_headers.find (hdr) != parent.out_headers.end()
396 || (oheaders.find(hdr) != oheaders.end());
397}
398
408inline
409const std::string& connection::get_ohdr (const std::string& hdr) const
410{
411 lock l (parent.hdr_lock);
412 auto idx = parent.out_headers.find (hdr);
413 if (idx != parent.out_headers.end ())
414 return idx->second;
415
416 return oheaders.at (hdr);
417}
418
424inline
425bool connection::has_qparam (const std::string& key)
426{
427 if (!query_parsed)
428 parse_query ();
429 return qparams.find (key) != qparams.end ();
430}
431
442inline
443const std::string& connection::get_qparam (const std::string& key)
444{
445 if (!query_parsed)
446 parse_query ();
447 return qparams.at (key);
448}
449
455inline
456bool connection::has_bparam (const std::string& key)
457{
458 if (!body_parsed)
459 parse_body ();
460 return bparams.find (key) != bparams.end ();
461}
462
472inline
473const std::string& connection::get_bparam (const std::string& key)
474{
475 static const std::string empty;
476 if (!body_parsed)
477 parse_body ();
478
479 return bparams.at (key);
480}
481
486inline
488{
489 return content_len;
490}
491
493inline
495{
496 return ws;
497}
498
499inline
501{
502 return iheaders;
503}
504
505
506//------------------------ http::server inline functions ----------------------
508inline
509const std::filesystem::path& server::docroot () const
510{
511 return root;
512}
513
515inline
517{
518 varlock.enter ();
519}
520
522inline
524{
525 varlock.leave ();
526}
527
532inline
534{
535 return varlock.try_enter ();
536}
537
538inline
539server::handle_info::handle_info (uri_handler h_, void* info_)
540 : h (h_)
541 , nfo (info_)
542 , in_use{std::make_shared<criticalsection> ()}
543{}
544
551inline std::ostream& operator<< (std::ostream& os, const str_pairs& hdrs)
552{
553 for (auto& hdr : hdrs)
554 {
555 os << hdr.first << ": " << hdr.second << "\r\n";
556 }
557 return os;
558}
559
560} // namespace mlib::http
Lightweight inter-thread synchronization.
Definition critsect.h:25
Representation of a HTTP client connection request.
const std::string & get_query() const
Return request query string (everything after '?' and before '#')
Definition httpd.h:338
bool has_ohdr(const std::string &hdr) const
Check if response has a header.
Definition httpd.h:392
void term() override
Finalization function called after run.
Definition httpd.cpp:308
const std::string & get_qparam(const std::string &key)
Return the value of a query parameter.
Definition httpd.h:443
sockstream & out()
Return socket object associated with this connection.
Definition httpd.h:494
const std::string & get_method() const
Return HTTP method (GET, POST, etc.) of the request.
Definition httpd.h:319
int serve_buffer(const BYTE *buffer, size_t sz)
Send the content of a buffer.
Definition httpd.cpp:726
const std::string & get_bparam(const std::string &key)
Return the value of a body parameter.
Definition httpd.h:473
const std::string & get_path() const
Return request target of this connection.
Definition httpd.h:305
int serve_file(const std::filesystem::path &file)
Send the content of a file.
Definition httpd.cpp:784
bool has_ihdr(const std::string &hdr) const
Check if request has a header.
Definition httpd.h:369
void respond(unsigned int code, const std::string &reason=std::string())
Send the beginning of HTTP response.
Definition httpd.cpp:934
bool has_qparam(const std::string &key)
Check if query has a parameter.
Definition httpd.h:425
const std::string & get_ihdr(const std::string &hdr) const
Return the value of a request header.
Definition httpd.h:382
int get_content_length() const
Return size of request body.
Definition httpd.h:487
const std::string & get_body() const
Return request body.
Definition httpd.h:347
bool has_bparam(const std::string &key)
Return true if request contains the given parameter in the request body.
Definition httpd.h:456
void serve404(const char *text=0)
Sends a 404 (page not found) response.
Definition httpd.cpp:442
const str_pairs & get_request_headers() const
Return all request headers.
Definition httpd.h:500
void add_ohdr(const std::string &hdr, const std::string &value)
Add or modify a response header.
Definition httpd.h:362
int serve_shtml(const std::filesystem::path &file)
Send the content of a file, processing any SSI directives.
Definition httpd.cpp:580
const std::string & get_ohdr(const std::string &hdr) const
Return the value of a response header.
Definition httpd.h:409
void redirect(const std::string &uri, unsigned int code=303)
Generate a HTTP redirect response to a new resource.
Definition httpd.cpp:900
connection(sock &socket, server &server)
Protected constructor used by mlib::http::server class to create a new connection thread.
Definition httpd.cpp:94
void run() override
The thread run loop.
Definition httpd.cpp:115
Small multi-threaded HTTP server.
Definition httpd.h:154
void release_varlock()
Release lock on server's variables.
Definition httpd.h:523
bool authenticate(const std::string &realm, const std::string &user, const std::string &pwd)
Verify user credentials for a realm.
Definition httpd.cpp:1268
void aquire_varlock()
Acquire lock on server's variables.
Definition httpd.h:516
int invoke_post_handler(connection &client)
Invoke a user defined handler in response to a POST or PUT request.
Definition httpd.cpp:1316
void add_realm(const char *realm, const char *uri)
Add a new access realm.
Definition httpd.cpp:1173
bool find_alias(const std::string &res, std::filesystem::path &path)
Retrieve the local file path mapped to a resource.
Definition httpd.cpp:1363
int invoke_handler(connection &client)
Invoke a user defined URI handler.
Definition httpd.cpp:1290
connection * make_thread(sock &connection)
Create an new mlib::http::connection object in response to a new client connection request.
Definition httpd.cpp:1065
void name(const char *nam)
Change server name.
Definition httpd.cpp:1049
bool add_user(const char *realm, const char *username, const char *pwd)
Add a new user to a relm or modifies password for an existing user.
Definition httpd.cpp:1186
void remove_ohdr(const std::string &hdr)
Remove a server response header.
Definition httpd.cpp:1088
static void delete_mime_type(const std::string &ext)
Remove a file type from the MIME type table.
Definition httpd.cpp:1160
static void add_mime_type(const std::string &ext, const std::string &type, bool shtml=false)
Add/change content of table matching MIME types to file extensions.
Definition httpd.cpp:1150
~server()
Destructor.
Definition httpd.cpp:1040
server(unsigned short port=0, unsigned int maxconn=0)
Constructor.
Definition httpd.cpp:1030
const std::string get_var(const std::string &name)
Return the current string representation of a variable.
Definition httpd.cpp:1417
const std::string & guess_mimetype(const std::filesystem::path &fn, bool &shtml)
Guess MIME type of a file and if SSI replacement should be enabled based on file extension.
Definition httpd.cpp:1486
void add_post_handler(const std::string &uri, uri_handler func, void *info=0)
Add or modify an POST handler function.
Definition httpd.cpp:1138
void add_handler(const std::string &uri, uri_handler func, void *info=0)
Add or modify an URI handler function.
Definition httpd.cpp:1123
vtype
SSI variables type.
Definition httpd.h:228
@ VT_UINT
unsigned int*
Definition httpd.h:236
@ VT_BOOL
bool*
Definition httpd.h:230
@ VT_FLOAT
float*
Definition httpd.h:239
@ VT_DOUBLE
double*
Definition httpd.h:240
@ VT_USHORT
unsigned short*
Definition httpd.h:234
@ VT_INT
int*
Definition httpd.h:235
@ VT_CHAR
char*
Definition httpd.h:231
@ VT_SHORT
short int*
Definition httpd.h:233
@ VT_UNKNOWN
illegal
Definition httpd.h:229
@ VT_ULONG
unsigned long*
Definition httpd.h:238
@ VT_LONG
long*
Definition httpd.h:237
@ VT_STRING
std::string*
Definition httpd.h:232
void add_ohdr(const std::string &hdr, const std::string &value)
Add or modify a server response header.
Definition httpd.cpp:1078
bool is_protected(const std::string &uri, std::string &realm)
Find the realm with longest matching path that covers an URI.
Definition httpd.cpp:1244
bool try_varlock()
Try to acquire lock on server's variables.
Definition httpd.h:533
const std::filesystem::path & docroot() const
Return current file origin.
Definition httpd.h:509
void add_alias(const std::string &uri, const std::string &path)
Maps a local file path to an URI resource path.
Definition httpd.cpp:1338
Automatic wrapper for critical sections.
Definition critsect.h:69
Encapsulation of a Windows socket.
Definition wsockstream.h:27
tcpserver(unsigned short port, const std::string &name=std::string(), unsigned int max_conn=0)
Opens the socket and initializes the connections table.
Definition tcpserver.cpp:70
void maxconn(unsigned int new_max)
Set maximum number of connections accepted.
Definition tcpserver.cpp:377
Wrapper for a Windows thread.
Definition thread.h:15
virtual const std::string & name() const
Return object's name.
Definition syncbase.h:60
std::function< int(connection &client, void *info)> uri_handler
User defined URL handler function.
Definition httpd.h:46
std::map< std::string, std::string, ci_less > str_pairs
Definition httpd.h:43
Case insensitive comparison function.
Definition httpd.h:34
Definition of tcpserver class.
generic_sockstream< std::iostream > sockstream
Bidirectional socket stream.
Definition wsockstream.h:262