MLIB
Loading...
Searching...
No Matches
http.h
Go to the documentation of this file.
1/*
2 Copyright (c) Mircea Neacsu (2014-2025) Licensed under MIT License.
3 This file 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 HTTP_MAX_HEADER 8192
18
20#define HTTP_TIMEOUT 30
21
24#define HTTP_OK 0
25#define HTTP_ERR_WRITE -1
26#define HTTP_ERR_FOPEN -2
27#define HTTP_ERR_FREAD -3
28#define HTTP_NO_HANDLER -4
29#define HTTP_CONTINUE 1
31
32namespace mlib::http {
33
34class connection;
35
37struct ci_less : public std::function<bool (std::string, std::string)>
38{
39 bool operator() (const std::string& lhs, const std::string& rhs) const
40 {
41 return _stricmp (lhs.c_str (), rhs.c_str ()) < 0;
42 }
43};
44
47typedef std::map<std::string, std::string, ci_less> str_pairs;
48
50typedef std::function<int (connection& client, void* info)> uri_handler;
51
53class connection : public thread
54{
55 friend class server;
56
57public:
58
60 const std::string& get_path () const;
61
63 const std::string& get_method () const;
64
66 const std::string& get_query () const;
67
69 const std::string& get_body () const;
70
71 void add_ohdr (const std::string& hdr, const std::string& value);
72
74 bool has_ihdr (const std::string& hdr) const;
75
77 const std::string& get_ihdr (const std::string& hdr) const;
78
80 const str_pairs& get_request_headers () const;
81
83 const str_pairs& get_response_headers () const;
84
86 bool has_ohdr (const std::string& hdr) const;
87
89 const std::string& get_ohdr (const std::string& hdr) const;
90
92 bool has_qparam (const std::string& key);
93
95 const std::string& get_qparam (const std::string& key);
96
98 bool has_bparam (const std::string& key);
99
101 const std::string& get_bparam (const std::string& key);
102
104 const std::string& get_auth_user ();
105
107 int get_content_length () const;
108
109 sockstream& out ();
110
111 void respond (unsigned int code, const std::string& reason = std::string());
112 void redirect (const std::string& uri, unsigned int code = 303);
113 void serve404 (const char* text = 0);
114 int serve_file (const std::filesystem::path& file);
115 int serve_shtml (const std::filesystem::path& file);
116 int serve_buffer (const BYTE* buffer, size_t sz);
117 int serve_buffer (const std::string& str);
118
119protected:
120 connection (sock& socket, server& server);
121
123 void run () override;
124
126 void term () override;
127
129 server& parent;
130
133
134private:
135 bool parse_request (const std::string& req);
136 bool parse_headers (const std::string& hdrs);
137 bool parse_body ();
138 void parse_query ();
139 void process_valid_request ();
140 void process_ssi (const char* request);
141 bool do_auth ();
142 void serve401 (const std::string& realm);
143 bool should_close ();
144 void request_init ();
145 void serve_options ();
146
147
148 std::string path_;
149 std::string query_;
150 std::string method_;
151 std::string http_version;
152 std::string body;
153 int content_len;
154 std::string part_boundary;
155 bool response_sent;
156 str_pairs oheaders;
157 str_pairs iheaders;
158 str_pairs qparams;
159 str_pairs bparams;
160 bool query_parsed, body_parsed;
161 std::string auth_user;
162 std::string auth_realm;
163
164 friend struct UnitTest_connection;
165};
166
168class server : public tcpserver
169{
170public:
171 explicit server (unsigned short port = 0, unsigned int maxconn = 0);
172 ~server ();
173
174 void add_ohdr (const std::string& hdr, const std::string& value);
175 void remove_ohdr (const std::string& hdr);
176
178 void add_handler (const std::string& uri, uri_handler func, void* info = 0);
179
181 void add_post_handler (const std::string& uri, uri_handler func, void* info = 0);
182
184 void add_user (const std::string& realm, const std::string& username, const std::string& pwd);
185
187 void remove_user (const std::string& realm, const std::string& username);
188
190 void add_secured_path (const std::string& realm, const std::string& uri);
191
197 template <typename T>
198 void add_var (const std::string& name, const T* addr, const char* fmt = nullptr)
199 {
200 constexpr vtype t = std::is_same_v<T, bool> ? VT_BOOL
201 : std::is_same_v<T, char> ? VT_CHAR
202 : std::is_same_v<T, std::string> ? VT_STRING
203 : std::is_same_v<T, short> ? VT_SHORT
204 : std::is_same_v<T, unsigned short> ? VT_USHORT
205 : std::is_same_v<T, int> ? VT_INT
206 : std::is_same_v<T, unsigned int> ? VT_UINT
207 : std::is_same_v<T, long> ? VT_LONG
208 : std::is_same_v<T, unsigned long> ? VT_ULONG
209 : VT_UNKNOWN;
210 static_assert (t != VT_UNKNOWN);
211 add_var (name, t, addr, fmt);
212 }
213
220 template <typename T>
221 std::enable_if_t<std::is_floating_point_v<T>> add_var (const std::string& name, const T* addr,
222 const char* fmt = nullptr,
223 double multiplier = 1.)
224 {
225 constexpr vtype t = std::is_same_v<T, float> ? VT_FLOAT
226 : std::is_same_v<T, float> ? VT_DOUBLE
227 : VT_UNKNOWN;
228 static_assert (t != VT_UNKNOWN);
229 add_var (name, t, addr, fmt, multiplier);
230 }
231
232 const std::string get_var (const std::string& name);
233 void aquire_varlock ();
234 void release_varlock ();
235 bool try_varlock ();
236
237 void name (const std::string& name_);
238 void docroot (const std::filesystem::path& path);
239 const std::filesystem::path& docroot () const;
240 void add_alias (const std::string& uri, const std::string& path);
241
242 void default_uri (const std::string& name);
243 const std::string& default_uri () const;
244
245 void keep_alive (unsigned int seconds);
246 unsigned int keep_alive () const;
247
248 static void add_mime_type (const std::string& ext, const std::string& type, bool shtml = false);
249 static void delete_mime_type (const std::string& ext);
250
251 bool is_protected (const std::string& uri, std::string& realm);
252 virtual bool verify_authorization (const std::string& realm, const std::string& user,
253 const std::string& password);
254protected:
271 int invoke_handler (connection& client);
272
273 int invoke_post_handler (connection& client);
274
275 bool find_alias (const std::string& res, std::filesystem::path& path);
276 virtual bool locate_resource (const std::string& res, std::filesystem::path& path);
277
278 const std::string& guess_mimetype (const std::filesystem::path& fn, bool& shtml);
280 void add_var (const std::string& name, vtype t, const void* addr, const char* fmt = nullptr,
281 double multiplier = 1.);
282private:
283
284 str_pairs out_headers;
285 mlib::criticalsection hdr_lock;
286
287 struct handle_info
288 {
289 handle_info (uri_handler h_, void* info_);
290
291 uri_handler h;
292 void* nfo;
293 std::shared_ptr<mlib::criticalsection> in_use;
294 };
295
296 bool locate_handler (const std::string& res, handle_info** ptr);
297
298 std::map<std::string, handle_info> handlers;
299 std::map<std::string, handle_info> post_handlers;
300
301 std::map<std::string, std::string> aliases;
302
304 struct var_info
305 {
306 std::string fmt;
307 vtype type;
308 const void* addr;
309 double multiplier;
310 };
311
313 std::map<std::string, var_info> variables;
314 mlib::criticalsection varlock;
315
317 struct user_inf
318 {
319 std::string name;
320 std::string pwd;
321 };
322
324 struct realm_descr
325 {
326 std::vector<std::string> paths;
327 std::vector<user_inf> credentials;
328 };
329
331 std::map<std::string, realm_descr> realms;
332 mlib::criticalsection realmlock;
333
334 std::filesystem::path root;
335 std::string defuri;
336 unsigned int timeout;
337
338 friend class connection;
339};
340
341/*==================== INLINE FUNCTIONS ===========================*/
342
355inline
356const std::string& connection::get_path () const
357{
358 return path_;
359};
360
370inline
371const std::string& connection::get_method () const
372{
373 return method_;
374};
375
390inline
391const std::string& connection::get_query () const
392{
393 return query_;
394};
395
399inline
400const std::string& connection::get_body () const
401{
402 return body;
403};
404
414inline
415void connection::add_ohdr (const std::string& hdr, const std::string& value)
416{
417 oheaders[hdr] = value;
418}
419
421inline
422bool connection::has_ihdr (const std::string& hdr) const
423{
424 return iheaders.find (hdr) != iheaders.end();
425}
426
434inline
435const std::string& connection::get_ihdr (const std::string& hdr) const
436{
437 return iheaders.at(hdr);
438}
439
443inline
444bool connection::has_ohdr (const std::string& hdr) const
445{
446 return oheaders.find(hdr) != oheaders.end();
447}
448
456inline
457const std::string& connection::get_ohdr (const std::string& hdr) const
458{
459 return oheaders.at (hdr);
460}
461
467inline
468bool connection::has_qparam (const std::string& key)
469{
470 if (!query_parsed)
471 parse_query ();
472 return qparams.find (key) != qparams.end ();
473}
474
485inline
486const std::string& connection::get_qparam (const std::string& key)
487{
488 if (!query_parsed)
489 parse_query ();
490 return qparams.at (key);
491}
492
498inline
499bool connection::has_bparam (const std::string& key)
500{
501 if (!body_parsed)
502 parse_body ();
503 return bparams.find (key) != bparams.end ();
504}
505
515inline
516const std::string& connection::get_bparam (const std::string& key)
517{
518 static const std::string empty;
519 if (!body_parsed)
520 parse_body ();
521
522 return bparams.at (key);
523}
524
525inline const std::string& connection::get_auth_user ()
526{
527 return auth_user;
528}
529
534inline
536{
537 return content_len;
538}
539
541inline
543{
544 return ws;
545}
546
547inline
549{
550 return iheaders;
551}
552
554{
555 return oheaders;
556}
557
558
559//------------------------ http::server inline functions ----------------------
560
562inline
563const std::filesystem::path& server::docroot () const
564{
565 return root;
566}
567
569inline
570void server::docroot (const std::filesystem::path& path)
571{
572 root = std::filesystem::absolute (path);
573}
574
575
577inline
579{
580 varlock.enter ();
581}
582
584inline
586{
587 varlock.leave ();
588}
589
594inline
596{
597 return varlock.try_enter ();
598}
599
601inline
602void server::default_uri (const std::string& name)
603{
604 defuri = name;
605}
606
608inline
609const std::string& server::default_uri () const
610{
611 return defuri;
612}
613
615inline
616void server::keep_alive (unsigned int seconds)
617{
618 timeout = seconds;
619}
620
622inline
623unsigned int server::keep_alive () const
624{
625 return timeout;
626}
627
628inline
629server::handle_info::handle_info (uri_handler h_, void* info_)
630 : h (h_)
631 , nfo (info_)
632 , in_use{std::make_shared<criticalsection> ()}
633{}
634
641inline std::ostream& operator<< (std::ostream& os, const str_pairs& hdrs)
642{
643 for (auto& hdr : hdrs)
644 {
645 os << hdr.first << ": " << hdr.second << "\r\n";
646 }
647 return os;
648}
649
650} // 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 http.h:391
bool has_ohdr(const std::string &hdr) const
Check if response has a header.
Definition http.h:444
void term() override
Cleanup function invoked when connection thread terminates.
Definition http.cpp:344
const std::string & get_qparam(const std::string &key)
Return the value of a query parameter.
Definition http.h:486
sockstream & out()
Return socket stream object associated with this connection.
Definition http.h:542
const std::string & get_method() const
Return HTTP method (GET, POST, etc.) of the request.
Definition http.h:371
int serve_buffer(const BYTE *buffer, size_t sz)
Send the content of a buffer.
Definition http.cpp:789
const std::string & get_bparam(const std::string &key)
Return the value of a body parameter.
Definition http.h:516
sockstream ws
socket stream used for send/receive operations
Definition http.h:132
const std::string & get_path() const
Return request target of this connection.
Definition http.h:356
int serve_file(const std::filesystem::path &file)
Send the content of a file.
Definition http.cpp:847
bool has_ihdr(const std::string &hdr) const
Check if request has a header.
Definition http.h:422
server & parent
HTTP server that created this connection.
Definition http.h:129
void respond(unsigned int code, const std::string &reason=std::string())
Send the beginning of HTTP response.
Definition http.cpp:1007
const str_pairs & get_response_headers() const
Return all response headers.
Definition http.h:553
bool has_qparam(const std::string &key)
Check if query has a parameter.
Definition http.h:468
const std::string & get_ihdr(const std::string &hdr) const
Return the value of a request header.
Definition http.h:435
int get_content_length() const
Return size of request body.
Definition http.h:535
const std::string & get_body() const
Return request body.
Definition http.h:400
bool has_bparam(const std::string &key)
Return true if request contains the given parameter in the request body.
Definition http.h:499
void serve404(const char *text=0)
Sends a 404 (page not found) response.
Definition http.cpp:507
const str_pairs & get_request_headers() const
Return all request headers.
Definition http.h:548
void add_ohdr(const std::string &hdr, const std::string &value)
Add or modify a response header.
Definition http.h:415
int serve_shtml(const std::filesystem::path &file)
Send the content of a file, processing any SSI directives.
Definition http.cpp:643
const std::string & get_ohdr(const std::string &hdr) const
Return the value of a response header.
Definition http.h:457
void redirect(const std::string &uri, unsigned int code=303)
Generate a HTTP redirect response to a new resource.
Definition http.cpp:973
connection(sock &socket, server &server)
Protected constructor used by mlib::http::server class to create a new connection thread.
Definition http.cpp:95
const std::string & get_auth_user()
Return authenticated user name.
Definition http.h:525
void run() override
The thread run loop.
Definition http.cpp:117
Small multi-threaded HTTP server.
Definition http.h:169
void release_varlock()
Release lock on server's variables.
Definition http.h:585
virtual bool locate_resource(const std::string &res, std::filesystem::path &path)
Try to map a resource to a local file.
Definition http.cpp:1501
void name(const std::string &name_)
Change server name.
Definition http.cpp:1136
void aquire_varlock()
Acquire lock on server's variables.
Definition http.h:578
int invoke_post_handler(connection &client)
Invoke a user defined handler in response to a POST or PUT request.
Definition http.cpp:1422
void add_secured_path(const std::string &realm, const std::string &uri)
Add an URI to a protection realm.
Definition http.cpp:1259
bool find_alias(const std::string &res, std::filesystem::path &path)
Retrieve the local file path mapped to a resource.
Definition http.cpp:1469
void remove_user(const std::string &realm, const std::string &username)
Remove an allowed user from an protection realm.
Definition http.cpp:1293
void add_user(const std::string &realm, const std::string &username, const std::string &pwd)
Add a new user to a protection realm.
Definition http.cpp:1275
int invoke_handler(connection &client)
Invoke a user defined URI handler.
Definition http.cpp:1397
connection * make_thread(sock &connection)
Create an new mlib::http::connection object in response to a new client connection request.
Definition http.cpp:1152
void remove_ohdr(const std::string &hdr)
Remove a server response header.
Definition http.cpp:1175
static void delete_mime_type(const std::string &ext)
Remove a file type from the MIME type table.
Definition http.cpp:1248
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 http.cpp:1238
const std::string & default_uri() const
Return default file name (initially index.html)
Definition http.h:609
~server()
Destructor.
Definition http.cpp:1126
std::enable_if_t< std::is_floating_point_v< T > > add_var(const std::string &name, const T *addr, const char *fmt=nullptr, double multiplier=1.)
Definition http.h:221
server(unsigned short port=0, unsigned int maxconn=0)
Constructor.
Definition http.cpp:1114
const std::string get_var(const std::string &name)
Return the current string representation of a variable.
Definition http.cpp:1544
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 http.cpp:1606
void add_post_handler(const std::string &uri, uri_handler func, void *info=0)
Add or modify an POST handler function.
Definition http.cpp:1225
void add_var(const std::string &name, const T *addr, const char *fmt=nullptr)
Definition http.h:198
void add_handler(const std::string &uri, uri_handler func, void *info=0)
Add or modify an URI handler function.
Definition http.cpp:1210
unsigned int keep_alive() const
Return timeout value for keep-alive connections.
Definition http.h:623
vtype
SSI variables type.
Definition http.h:257
@ VT_UINT
unsigned int*
Definition http.h:265
@ VT_BOOL
bool*
Definition http.h:259
@ VT_FLOAT
float*
Definition http.h:268
@ VT_DOUBLE
double*
Definition http.h:269
@ VT_USHORT
unsigned short*
Definition http.h:263
@ VT_INT
int*
Definition http.h:264
@ VT_CHAR
char*
Definition http.h:260
@ VT_SHORT
short int*
Definition http.h:262
@ VT_UNKNOWN
illegal
Definition http.h:258
@ VT_ULONG
unsigned long*
Definition http.h:267
@ VT_LONG
long*
Definition http.h:266
@ VT_STRING
std::string*
Definition http.h:261
void add_ohdr(const std::string &hdr, const std::string &value)
Add or modify a server response header.
Definition http.cpp:1165
bool is_protected(const std::string &uri, std::string &realm)
Find if URI is covered by a protection realm.
Definition http.cpp:1313
bool try_varlock()
Try to acquire lock on server's variables.
Definition http.h:595
const std::filesystem::path & docroot() const
Return current root path as absolute path.
Definition http.h:563
void add_alias(const std::string &uri, const std::string &path)
Maps a local file path to an URI resource path.
Definition http.cpp:1444
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
@ seconds
Degrees, minutes, seconds format (DD°MM'SS.sss")
Definition convert.h:249
std::function< int(connection &client, void *info)> uri_handler
User defined URL handler function.
Definition http.h:50
std::map< std::string, std::string, ci_less > str_pairs
Definition http.h:47
std::ostream & operator<<(std::ostream &strm, const mlib::inaddr &addr)
Serialize an address as '<hostname>:<port>'.
Definition inaddr.h:127
Case insensitive comparison function.
Definition http.h:38
Definition of tcpserver class.
generic_sockstream< std::iostream > sockstream
Bidirectional socket stream.
Definition wsockstream.h:262