join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
httpserver.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_SERVICES_HTTPSERVER_HPP
26#define JOIN_SERVICES_HTTPSERVER_HPP
27
28// libjoin.
29#include <join/httpmessage.hpp>
30#include <join/filesystem.hpp>
31#include <join/acceptor.hpp>
32#include <join/version.hpp>
33#include <join/thread.hpp>
34#include <join/cache.hpp>
35
36// C++.
37#include <sys/eventfd.h>
38#include <thread>
39#include <memory>
40#include <vector>
41
42// C.
43#include <fnmatch.h>
44
45namespace join
46{
57
61 template <class Protocol>
63 {
64 using Handler = std::function<void (typename Protocol::Worker*)>;
65 using Access = std::function<bool (const std::string&, const std::string&, std::error_code&)>;
66
69 std::string directory;
70 std::string name;
71 std::string alias;
74 };
75
79 template <class Protocol>
80 class BasicHttpWorker : public Protocol::Stream
81 {
82 public:
85
91 : _server (server)
92 , _thread ([this] () {
93 work ();
94 })
95 {
96 }
97
102 BasicHttpWorker (const BasicHttpWorker& other) = delete;
103
110
116
123
128 {
129 this->_thread.join ();
130 }
131
136 {
137 // restore concrete stream.
138 this->clearEncoding ();
139
140 // set missing response headers.
141 if (!this->_response.hasHeader ("Date"))
142 {
143 std::stringstream gmt;
144 std::time_t ti = std::time (nullptr);
145 gmt << std::put_time (std::gmtime (&ti), "%a, %d %b %Y %H:%M:%S GMT");
146 this->_response.header ("Date", gmt.str ());
147 }
148 if (!this->_response.hasHeader ("Server"))
149 {
150 this->_response.header ("Server", "join/" JOIN_VERSION);
151 }
152 if (!this->_response.hasHeader ("Connection"))
153 {
154 if (this->_max && compareNoCase (this->_request.header ("Connection"), "keep-alive"))
155 {
156 std::stringstream keepAlive;
157 keepAlive << "timeout=" << this->_server->keepAliveTimeout ().count ()
158 << ", max=" << this->_server->keepAliveMax ();
159 this->_response.header ("Keep-Alive", keepAlive.str ());
160 this->_response.header ("Connection", "Keep-Alive");
161 }
162 else
163 {
164 this->_response.header ("Connection", "close");
165 this->_max = 0;
166 }
167 }
168 if (this->encrypted () && !this->_response.hasHeader ("Strict-Transport-Security"))
169 {
170 this->_response.header ("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload");
171 }
172 if (!this->_response.hasHeader ("Content-Security-Policy"))
173 {
174 this->_response.header (
175 "Content-Security-Policy",
176 "default-src 'self'; object-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'");
177 }
178 if (!this->_response.hasHeader ("X-XSS-Protection"))
179 {
180 this->_response.header ("X-XSS-Protection", "1; mode=block");
181 }
182 if (!this->_response.hasHeader ("X-Content-Type-Options"))
183 {
184 this->_response.header ("X-Content-Type-Options", "nosniff");
185 }
186 if (!this->_response.hasHeader ("X-Frame-Options"))
187 {
188 this->_response.header ("X-Frame-Options", "SAMEORIGIN");
189 }
190
191 // write response headers.
192 this->_response.writeHeaders (*this);
193
194 // set encoding.
195 if (this->_response.hasHeader ("Transfer-Encoding"))
196 {
197 this->setEncoding (join::rsplit (this->_response.header ("Transfer-Encoding"), ","));
198 }
199 if (this->_response.hasHeader ("Content-Encoding"))
200 {
201 this->setEncoding (join::rsplit (this->_response.header ("Content-Encoding"), ","));
202 }
203 }
204
210 void sendError (const std::string& status, const std::string& reason)
211 {
212 // set error response.
213 this->_response.response (status, reason);
214
215 // stop keepalive.
216 this->_response.header ("Connection", "close");
217 this->_max = 0;
218
219 // send headers.
220 this->sendHeaders ();
221
222 // flush data.
223 this->flush ();
224 }
225
232 void sendRedirect (const std::string& status, const std::string& reason, const std::string& location = {})
233 {
234 std::string payload;
235
236 // set redirect response.
237 this->_response.response (status, reason);
238
239 // set redirect message payload.
240 if (!location.empty ())
241 {
242 payload += "<html>";
243 payload += "<head>";
244 payload += "<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">";
245 payload += "<title>" + status + " " + reason + "</title>";
246 payload += "</head>";
247 payload += "<body>";
248 payload += "<h1>" + status + " " + reason + "</h1>";
249 payload += "The document has moved <a href=\"" + location + "\">here</a>";
250 payload += "</body>";
251 payload += "</html>";
252 }
253
254 // set content.
255 if (payload.size ())
256 {
257 this->_response.header ("Content-Length", std::to_string (payload.size ()));
258 this->_response.header ("Content-Type", "text/html");
259 this->_response.header ("Cache-Control", "no-cache");
260 }
261
262 // send headers.
263 this->sendHeaders ();
264
265 // send payload.
266 if (payload.size ())
267 {
268 this->write (payload.c_str (), payload.size ());
269 }
270
271 // flush data.
272 this->flush ();
273 }
274
279 void sendFile (const std::string& path)
280 {
281 struct stat sbuf;
282
283 // get file.
284 void* addr = this->_server->_cache.get (path, sbuf);
285 if (addr == nullptr || S_ISDIR (sbuf.st_mode))
286 {
287 this->sendError ("404", "Not Found");
288 return;
289 }
290
291 // check modif time.
292 std::stringstream modifTime;
293 modifTime << std::put_time (std::gmtime (&sbuf.st_ctime), "%a, %d %b %Y %H:%M:%S GMT");
294 if (compareNoCase (this->_request.header ("If-Modified-Since"), modifTime.str ()))
295 {
296 this->sendRedirect ("304", "Not Modified");
297 return;
298 }
299
300 // set modif time.
301 this->_response.header ("Last-Modified", modifTime.str ());
302
303 // set content.
304 this->_response.header ("Content-Length", std::to_string (sbuf.st_size));
305 this->_response.header ("Content-Type", join::mime (path));
306 this->_response.header ("Cache-Control", "no-cache");
307
308 // send headers.
309 this->sendHeaders ();
310
311 // check method.
312 if (this->_request.method () == HttpMethod::Get)
313 {
314 // send file.
315 this->write (static_cast<char*> (addr), sbuf.st_size);
316 }
317
318 // flush data.
319 this->flush ();
320 }
321
327 bool hasHeader (const std::string& name) const
328 {
329 return this->_request.hasHeader (name);
330 }
331
337 std::string header (const std::string& name) const
338 {
339 return this->_request.header (name);
340 }
341
346 size_t contentLength () const
347 {
348 return this->_request.contentLength ();
349 }
350
356 void header (const std::string& name, const std::string& val)
357 {
358 return this->_response.header (name, val);
359 }
360
361 protected:
365 void work ()
366 {
367 fd_set setfd;
368 FD_ZERO (&setfd);
369 int fdmax = -1;
370
371 FD_SET (this->_server->_event, &setfd);
372 fdmax = std::max (fdmax, this->_server->_event);
373 FD_SET (this->_server->_acceptor.handle (), &setfd);
374 fdmax = std::max (fdmax, this->_server->_acceptor.handle ());
375
376 for (;;)
377 {
378 {
379 ScopedLock<Mutex> lock (this->_server->_mutex);
380
381 fd_set fdset = setfd;
382 int nset = ::select (fdmax + 1, &fdset, nullptr, nullptr, nullptr);
383 if (nset > 0)
384 {
385 if (FD_ISSET (this->_server->_event, &fdset))
386 {
387 uint64_t val = 0;
388 [[maybe_unused]] ssize_t bytes = ::read (this->_server->_event, &val, sizeof (uint64_t));
389 return;
390 }
391
392 if (FD_ISSET (this->_server->_acceptor.handle (), &fdset))
393 {
394 this->_sockbuf.socket () = this->_server->accept ();
395 this->_sockbuf.timeout (this->_server->keepAliveTimeout ().count () * 1000);
396 }
397 }
398 }
399
400 this->processRequest ();
401 }
402 }
403
408 {
409 this->_max = this->_server->keepAliveMax ();
410
411 do
412 {
413 if (this->readRequest () == -1)
414 {
415 this->cleanUp ();
416 break;
417 }
418
419 this->writeResponse ();
420 this->cleanUp ();
421 }
422 while ((this->_max < 0) || (--this->_max != 0));
423
424 this->endRequest ();
425 }
426
432 {
433 // restore concrete stream.
434 this->clearEncoding ();
435
436 // prepare a standard response.
437 this->_response.response ("200", "OK");
438
439 // read request headers.
440 if (this->_request.readHeaders (*this) == -1)
441 {
443 {
444 this->sendError ("400", "Bad Request");
445 }
447 {
448 this->sendError ("405", "Method Not Allowed");
449 }
451 {
452 this->sendError ("494", "Request Header Too Large");
453 }
454 return -1;
455 }
456
457 // check host.
458 if (this->_request.host ().empty ())
459 {
460 this->sendError ("400", "Bad Request");
461 return -1;
462 }
463
464 // set encoding.
465 if (this->_request.hasHeader ("Transfer-Encoding"))
466 {
467 this->setEncoding (join::rsplit (this->_request.header ("Transfer-Encoding"), ","));
468 }
469 if (this->_request.hasHeader ("Content-Encoding"))
470 {
471 this->setEncoding (join::rsplit (this->_request.header ("Content-Encoding"), ","));
472 }
473
474 return 0;
475 }
476
481 {
482 Content* content = this->_server->findContent (this->_request.method (), this->_request.path ());
483 if (content == nullptr)
484 {
485 this->sendError ("404", "Not Found");
486 return;
487 }
488
489 if (content->access != nullptr)
490 {
491 if (!this->_request.hasHeader ("Authorization"))
492 {
493 this->sendError ("401", "Unauthorized");
494 return;
495 }
496
497 std::error_code err;
498 if (!content->access (this->_request.auth (), this->_request.credentials (), err))
499 {
500 if (err == HttpErrc::Unauthorized)
501 {
502 this->sendError ("401", "Unauthorized");
503 }
504 else if (err == HttpErrc::Forbidden)
505 {
506 this->sendError ("403", "Forbidden");
507 }
508 return;
509 }
510 }
511
512 std::string alias (content->alias);
513 if (!alias.empty ())
514 {
515 join::replaceAll (alias, "$root", this->_server->baseLocation ());
516 join::replaceAll (alias, "$scheme", this->_server->scheme ());
517 join::replaceAll (alias, "$host", this->_request.host ());
518 join::replaceAll (alias, "$port", std::to_string (this->localEndpoint ().port ()));
519 join::replaceAll (alias, "$path", this->_request.path ());
520 join::replaceAll (alias, "$query", this->_request.query ());
521 join::replaceAll (alias, "$urn", this->_request.urn ());
522 }
523
524 if (content->type == HttpContentType::Root)
525 {
526 this->sendFile (this->_server->baseLocation () + this->_request.path ());
527 }
528 else if (content->type == HttpContentType::Alias)
529 {
530 this->sendFile (alias);
531 }
532 else if (content->type == HttpContentType::Exec)
533 {
534 if (content->handler == nullptr)
535 {
536 this->sendError ("500", "Internal Server Error");
537 return;
538 }
539 content->handler (this);
540 }
541 else if (content->type == HttpContentType::Redirect)
542 {
543 if (this->_request.version () == "HTTP/1.1")
544 {
545 this->sendRedirect ("307", "Temporary Redirect", alias);
546 }
547 else
548 {
549 this->sendRedirect ("302", "Found", alias);
550 }
551 }
552 }
553
557 void cleanUp ()
558 {
559 this->_request.clear ();
560 this->_response.clear ();
561 }
562
567 {
568 this->disconnect ();
569 this->close ();
570 }
571
576 void setEncoding (const std::vector<std::string>& encodings)
577 {
578 for (auto const& encoding : encodings)
579 {
580 if (encoding.find ("gzip") != std::string::npos)
581 {
582 this->_streambuf = new Zstreambuf (this->_streambuf, Zstream::Gzip, this->_wrapped);
583 this->_wrapped = true;
584 }
585 else if (encoding.find ("deflate") != std::string::npos)
586 {
587 this->_streambuf = new Zstreambuf (this->_streambuf, Zstream::Deflate, this->_wrapped);
588 this->_wrapped = true;
589 }
590 else if (encoding.find ("chunked") != std::string::npos)
591 {
592 this->_streambuf = new Chunkstreambuf (this->_streambuf, this->_wrapped);
593 this->_wrapped = true;
594 }
595 }
596
597 this->set_rdbuf (this->_streambuf);
598 }
599
604 {
605 if (this->_wrapped && this->_streambuf)
606 {
607 delete this->_streambuf;
608 this->_streambuf = nullptr;
609 }
610
611 this->_streambuf = &this->_sockbuf;
612 this->_wrapped = false;
613
614 this->set_rdbuf (this->_streambuf);
615 }
616
618 int _max = 0;
619
622
625
627 std::streambuf* _streambuf = nullptr;
628
630 bool _wrapped = false;
631
634
637 };
638
642 template <class Protocol>
644 {
645 public:
648 using Handler = typename Content::Handler;
649 using Access = typename Content::Access;
650 using Endpoint = typename Protocol::Endpoint;
651 using Socket = typename Protocol::Socket;
652 using Acceptor = typename Protocol::Acceptor;
653
658 BasicHttpServer (size_t workers = std::thread::hardware_concurrency ())
659 : _event (eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC | EFD_SEMAPHORE))
660 , _nworkers (workers)
661 , _baseLocation ("/var/www")
662 , _keepTimeout (10)
663 {
664 [[maybe_unused]] int res = chdir (this->_baseLocation.c_str ());
665 }
666
671 BasicHttpServer (const BasicHttpServer& other) = delete;
672
679
685
692
697 {
698 this->_acceptor.close ();
699 this->_contents.clear ();
700 ::close (this->_event);
701 }
702
708 int create (const Endpoint& endpoint) noexcept
709 {
710 if (this->_acceptor.create (endpoint) == -1)
711 {
712 return -1;
713 }
714
715 for (size_t nworkers = 0; nworkers < this->_nworkers; ++nworkers)
716 {
717 this->_workers.emplace_back (new Worker (this));
718 }
719
720 return 0;
721 }
722
726 void close () noexcept
727 {
728 uint64_t val = this->_nworkers;
729 [[maybe_unused]] ssize_t bytes = ::write (this->_event, &val, sizeof (uint64_t));
730 this->_workers.clear ();
731 this->_acceptor.close ();
732 }
733
738 virtual Socket accept () const
739 {
740 return this->_acceptor.accept ();
741 }
742
747 void baseLocation (const std::string& path)
748 {
749 this->_baseLocation = path;
750
751 if (*this->_baseLocation.rbegin () == '/')
752 {
753 this->_baseLocation.pop_back ();
754 }
755
756 [[maybe_unused]] int res = chdir (this->_baseLocation.c_str ());
757 }
758
763 const std::string& baseLocation () const
764 {
765 return this->_baseLocation;
766 }
767
773 void keepAlive (std::chrono::seconds timeout, int max = 1000)
774 {
775 this->_keepTimeout = timeout;
776 this->_keepMax = max;
777 }
778
783 std::chrono::seconds keepAliveTimeout () const
784 {
785 return this->_keepTimeout;
786 }
787
792 int keepAliveMax () const
793 {
794 return this->_keepMax;
795 }
796
801 virtual std::string scheme () const
802 {
803 return "http";
804 }
805
813 Content* addDocumentRoot (const std::string& dir, const std::string& name, const Access& access = nullptr)
814 {
815 Content* newEntry = new Content;
816 if (newEntry != nullptr)
817 {
818 newEntry->methods = Head | Get;
819 newEntry->type = Root;
820 newEntry->directory = dir;
821 newEntry->name = name;
822 newEntry->handler = nullptr;
823 newEntry->access = access;
824 this->_contents.emplace_back (newEntry);
825 }
826
827 return newEntry;
828 }
829
838 Content* addAlias (const std::string& dir, const std::string& name, const std::string& alias,
839 const Access& access = nullptr)
840 {
841 Content* newEntry = new Content;
842 if (newEntry != nullptr)
843 {
844 newEntry->methods = Head | Get;
845 newEntry->type = Alias;
846 newEntry->directory = dir;
847 newEntry->name = name;
848 newEntry->alias = alias;
849 newEntry->handler = nullptr;
850 newEntry->access = access;
851 this->_contents.emplace_back (newEntry);
852 }
853
854 return newEntry;
855 }
856
866 Content* addExecute (const HttpMethod methods, const std::string& dir, const std::string& name,
867 const Handler& handler, const Access& access = nullptr)
868 {
869 Content* newEntry = new Content;
870 if (newEntry != nullptr)
871 {
872 newEntry->methods = methods;
873 newEntry->type = Exec;
874 newEntry->directory = dir;
875 newEntry->name = name;
876 newEntry->handler = handler;
877 newEntry->access = access;
878 this->_contents.emplace_back (newEntry);
879 }
880
881 return newEntry;
882 }
883
892 Content* addRedirect (const std::string& dir, const std::string& name, const std::string& location,
893 const Access& access = nullptr)
894 {
895 Content* newEntry = new Content;
896 if (newEntry != nullptr)
897 {
898 newEntry->methods = Head | Get | Put | Post | Delete;
899 newEntry->type = Redirect;
900 newEntry->directory = dir;
901 newEntry->name = name;
902 newEntry->alias = location;
903 newEntry->handler = nullptr;
904 newEntry->access = access;
905 this->_contents.emplace_back (newEntry);
906 }
907
908 return newEntry;
909 }
910
911 protected:
918 Content* findContent (HttpMethod method, const std::string& path) const
919 {
920 std::string directory = join::base (path);
921 std::string name = join::filename (path);
922
923 for (auto const& content : this->_contents)
924 {
925 if (content->methods & method)
926 {
927 if (fnmatch (content->directory.c_str (), directory.c_str (), FNM_CASEFOLD) == 0)
928 {
929 if (fnmatch (content->name.c_str (), name.c_str (), FNM_CASEFOLD) == 0)
930 {
931 return content.get ();
932 }
933 }
934 }
935 }
936
937 return nullptr;
938 }
939
942
944 int _event = -1;
945
947 size_t _nworkers;
948
950 std::vector<std::unique_ptr<Worker>> _workers;
951
954
956 std::vector<std::unique_ptr<Content>> _contents;
957
959 std::string _baseLocation;
960
962 std::chrono::seconds _keepTimeout;
963
965 int _keepMax = 1000;
966
969
971 friend Worker;
972 };
973
977 template <class Protocol>
978 class BasicHttpSecureServer : public BasicHttpServer<Protocol>
979 {
980 public:
983 using Handler = typename Content::Handler;
984 using Access = typename Content::Access;
985 using Endpoint = typename Protocol::Endpoint;
986 using Socket = typename Protocol::Socket;
987 using Acceptor = typename Protocol::Acceptor;
988
993 BasicHttpSecureServer (size_t workers = std::thread::hardware_concurrency ())
994 : BasicHttpServer<Protocol> (workers)
995 {
996 }
997
1003
1010
1016
1023
1027 virtual ~BasicHttpSecureServer () = default;
1028
1033 Socket accept () const override
1034 {
1035 return this->_acceptor.acceptEncrypted ();
1036 }
1037
1044 int setCertificate (const std::string& cert, const std::string& key = "")
1045 {
1046 return this->_acceptor.setCertificate (cert, key);
1047 }
1048
1054 int setCaCertificate (const std::string& caFile)
1055 {
1056 return this->_acceptor.setCaCertificate (caFile);
1057 }
1058
1064 void setVerify (bool verify, int depth = -1)
1065 {
1066 return this->_acceptor.setVerify (verify, depth);
1067 }
1068
1074 int setCipher (const std::string& cipher)
1075 {
1076 return this->_acceptor.setCipher (cipher);
1077 }
1078
1084 int setCipher_1_3 (const std::string& cipher)
1085 {
1086 return this->_acceptor.setCipher_1_3 (cipher);
1087 }
1088
1089#if OPENSSL_VERSION_NUMBER >= 0x30000000L
1095 int setCurve (const std::string& curves)
1096 {
1097 return this->_acceptor.setCurve (curves);
1098 }
1099#endif
1100
1105 virtual std::string scheme () const override
1106 {
1107 return "https";
1108 }
1109
1111 friend Worker;
1112 };
1113}
1114
1115#endif
basic HTTPS server.
Definition httpserver.hpp:979
BasicHttpSecureServer(size_t workers=std::thread::hardware_concurrency())
create the HTTPS server instance.
Definition httpserver.hpp:993
typename Protocol::Acceptor Acceptor
Definition httpserver.hpp:987
typename Protocol::Endpoint Endpoint
Definition httpserver.hpp:985
int setCertificate(const std::string &cert, const std::string &key="")
set the certificate and the private key.
Definition httpserver.hpp:1044
typename Content::Handler Handler
Definition httpserver.hpp:983
friend Worker
friendship with worker.
Definition httpserver.hpp:1111
BasicHttpSecureServer(const BasicHttpSecureServer &other)=delete
create instance by copy.
int setCaCertificate(const std::string &caFile)
Set the location of the trusted CA certificate.
Definition httpserver.hpp:1054
typename Protocol::Socket Socket
Definition httpserver.hpp:986
BasicHttpSecureServer & operator=(const BasicHttpSecureServer &other)=delete
assign instance by copy.
int setCipher(const std::string &cipher)
set the cipher list (TLSv1.2 and below).
Definition httpserver.hpp:1074
Socket accept() const override
accept new connection and fill in the client object with connection parameters.
Definition httpserver.hpp:1033
virtual ~BasicHttpSecureServer()=default
destroy the HTTPS server.
typename Content::Access Access
Definition httpserver.hpp:984
virtual std::string scheme() const override
get scheme.
Definition httpserver.hpp:1105
void setVerify(bool verify, int depth=-1)
Enable/Disable the verification of the peer certificate.
Definition httpserver.hpp:1064
BasicHttpSecureServer(BasicHttpSecureServer &&other)=delete
create instance by move.
int setCipher_1_3(const std::string &cipher)
set the cipher list (TLSv1.3).
Definition httpserver.hpp:1084
basic HTTP server.
Definition httpserver.hpp:644
BasicHttpServer(size_t workers=std::thread::hardware_concurrency())
create the HTTP server instance.
Definition httpserver.hpp:658
typename Content::Handler Handler
Definition httpserver.hpp:648
typename Protocol::Socket Socket
Definition httpserver.hpp:651
Content * addAlias(const std::string &dir, const std::string &name, const std::string &alias, const Access &access=nullptr)
map an URL to filesystem replacing URL path by the specified path.
Definition httpserver.hpp:838
typename Content::Access Access
Definition httpserver.hpp:649
std::vector< std::unique_ptr< Worker > > _workers
workers.
Definition httpserver.hpp:950
std::string _baseLocation
base location.
Definition httpserver.hpp:959
Content * addExecute(const HttpMethod methods, const std::string &dir, const std::string &name, const Handler &handler, const Access &access=nullptr)
map an URL to a callback.
Definition httpserver.hpp:866
void keepAlive(std::chrono::seconds timeout, int max=1000)
set HTTP keep alive.
Definition httpserver.hpp:773
const std::string & baseLocation() const
get file base location.
Definition httpserver.hpp:763
typename Protocol::Endpoint Endpoint
Definition httpserver.hpp:650
Content * addRedirect(const std::string &dir, const std::string &name, const std::string &location, const Access &access=nullptr)
map an URL to a redirection.
Definition httpserver.hpp:892
Acceptor _acceptor
acceptor.
Definition httpserver.hpp:941
void baseLocation(const std::string &path)
set file base location.
Definition httpserver.hpp:747
int _keepMax
keep alive max.
Definition httpserver.hpp:965
typename Protocol::Acceptor Acceptor
Definition httpserver.hpp:652
virtual Socket accept() const
accept new connection.
Definition httpserver.hpp:738
void close() noexcept
close server.
Definition httpserver.hpp:726
virtual ~BasicHttpServer()
destroy the HTTP server.
Definition httpserver.hpp:696
Content * findContent(HttpMethod method, const std::string &path) const
find content.
Definition httpserver.hpp:918
Cache _cache
file cache.
Definition httpserver.hpp:968
std::vector< std::unique_ptr< Content > > _contents
contents.
Definition httpserver.hpp:956
BasicHttpServer & operator=(const BasicHttpServer &other)=delete
assign instance by copy.
Content * addDocumentRoot(const std::string &dir, const std::string &name, const Access &access=nullptr)
map an URL to filesystem adding URL path to the base location.
Definition httpserver.hpp:813
friend Worker
friendship with worker.
Definition httpserver.hpp:971
int keepAliveMax() const
get HTTP keep alive max.
Definition httpserver.hpp:792
int _event
gracefully stop all workers.
Definition httpserver.hpp:944
int create(const Endpoint &endpoint) noexcept
create server.
Definition httpserver.hpp:708
BasicHttpContent< Protocol > Content
Definition httpserver.hpp:647
std::chrono::seconds keepAliveTimeout() const
get HTTP keep alive timeout.
Definition httpserver.hpp:783
size_t _nworkers
number of workers.
Definition httpserver.hpp:947
std::chrono::seconds _keepTimeout
keep alive timeout.
Definition httpserver.hpp:962
BasicHttpServer(BasicHttpServer &&other)=delete
create instance by move.
Mutex _mutex
accept protection mutex.
Definition httpserver.hpp:953
BasicHttpServer(const BasicHttpServer &other)=delete
create instance by copy.
virtual std::string scheme() const
get scheme.
Definition httpserver.hpp:801
basic HTTP worker.
Definition httpserver.hpp:81
void setEncoding(const std::vector< std::string > &encodings)
set stream encoding.
Definition httpserver.hpp:576
void clearEncoding()
clear stream encoding.
Definition httpserver.hpp:603
std::string header(const std::string &name) const
get HTTP request header by name.
Definition httpserver.hpp:337
std::streambuf * _streambuf
HTTP stream buffer.
Definition httpserver.hpp:627
bool hasHeader(const std::string &name) const
checks if there is a HTTP request header with the specified name.
Definition httpserver.hpp:327
BasicHttpWorker(BasicHttpWorker &&other)=delete
create instance by move.
HttpRequest _request
HTTP request.
Definition httpserver.hpp:621
void sendHeaders()
send headers.
Definition httpserver.hpp:135
void writeResponse()
write the HTTP response.
Definition httpserver.hpp:480
void sendFile(const std::string &path)
send a file.
Definition httpserver.hpp:279
void header(const std::string &name, const std::string &val)
add header to the HTTP response.
Definition httpserver.hpp:356
int _max
max requests.
Definition httpserver.hpp:618
BasicHttpWorker(const BasicHttpWorker &other)=delete
create instance by copy.
void cleanUp()
clean all.
Definition httpserver.hpp:557
BasicHttpWorker & operator=(const BasicHttpWorker &other)=delete
assign instance by copy.
bool _wrapped
HTTP stream status.
Definition httpserver.hpp:630
void sendRedirect(const std::string &status, const std::string &reason, const std::string &location={})
send redirect message.
Definition httpserver.hpp:232
void endRequest()
end the HTTP request.
Definition httpserver.hpp:566
HttpResponse _response
HTTP response.
Definition httpserver.hpp:624
Server * _server
HTTP server.
Definition httpserver.hpp:633
int readRequest()
read the HTTP request.
Definition httpserver.hpp:431
void processRequest()
process the HTTP request.
Definition httpserver.hpp:407
virtual ~BasicHttpWorker()
destroy worker thread.
Definition httpserver.hpp:127
Thread _thread
thread.
Definition httpserver.hpp:636
void sendError(const std::string &status, const std::string &reason)
send error message.
Definition httpserver.hpp:210
void work()
worker thread routine.
Definition httpserver.hpp:365
size_t contentLength() const
get content length.
Definition httpserver.hpp:346
BasicHttpWorker(Server *server)
create the worker instance.
Definition httpserver.hpp:90
File cache.
Definition cache.hpp:45
void * get(const std::string &fileName, struct stat &sbuf)
get or create the cache entry for the given file.
Definition cache.cpp:52
chunk stream buffer.
Definition chunkstream.hpp:37
size_t contentLength() const
get content length.
Definition httpmessage.cpp:283
const std::string & version() const
get HTTP version.
Definition httpmessage.cpp:185
virtual int readHeaders(std::istream &in)
read HTTP header from the given input stream.
Definition httpmessage.cpp:304
bool hasHeader(const std::string &name) const
checks if there is a header with the specified name.
Definition httpmessage.cpp:203
std::string header(const std::string &name) const
get header by name.
Definition httpmessage.cpp:212
HTTP request.
Definition httpmessage.hpp:353
const std::string & path() const
get path.
Definition httpmessage.cpp:483
std::string urn() const
get URN.
Definition httpmessage.cpp:601
HttpMethod method() const
get request method.
Definition httpmessage.cpp:442
virtual void clear() override
clear HTTP message.
Definition httpmessage.cpp:654
std::string host() const
get host.
Definition httpmessage.cpp:610
std::string query() const
get query.
Definition httpmessage.cpp:585
HTTP response.
Definition httpmessage.hpp:559
void response(const std::string &status, const std::string &reason={})
set HTTP response status.
Definition httpmessage.cpp:961
virtual int writeHeaders(std::ostream &out) const override
write HTTP headers to the given output stream.
Definition httpmessage.cpp:982
virtual void clear() override
clear HTTP message.
Definition httpmessage.cpp:971
class used to protect shared data from being simultaneously accessed by multiple threads.
Definition mutex.hpp:37
class owning a mutex for the duration of a scoped block.
Definition mutex.hpp:246
thread class.
Definition thread.hpp:148
void join() noexcept
block the current thread until the running thread finishes its execution.
Definition thread.cpp:252
@ Deflate
Definition zstream.hpp:128
@ Gzip
Definition zstream.hpp:130
zlib stream buffer.
Definition zstream.hpp:40
const std::string key(65, 'a')
key.
Definition acceptor.hpp:32
HttpMethod
enumeration of HTTP methods.
Definition httpmessage.hpp:112
@ Post
Definition httpmessage.hpp:116
@ Put
Definition httpmessage.hpp:115
@ Delete
Definition httpmessage.hpp:118
@ Head
Definition httpmessage.hpp:113
@ Get
Definition httpmessage.hpp:114
std::string base(const std::string &filepath)
get base path of the specified file.
Definition filesystem.hpp:41
std::string filename(const std::string &filepath)
get file name of the specified file.
Definition filesystem.hpp:56
std::string mime(const std::string &filepath)
get mime type of the specified file.
Definition filesystem.hpp:86
bool compareNoCase(const std::string &a, const std::string &b)
case insensitive string comparison.
Definition utils.hpp:196
HttpContentType
HTTP content Type.
Definition httpserver.hpp:51
@ Root
Definition httpserver.hpp:52
@ Alias
Definition httpserver.hpp:53
@ Exec
Definition httpserver.hpp:54
@ Redirect
Definition httpserver.hpp:55
thread_local std::error_code lastError
last error.
Definition error.cpp:32
std::vector< std::string > rsplit(const std::string &in, const std::string &delim)
split a string in reverse order using a delimiter.
Definition utils.hpp:283
std::string & replaceAll(std::string &str, const std::string &toReplace, const std::string &by)
replace all occurrences of a substring.
Definition utils.hpp:240
basic HTTP content.
Definition httpserver.hpp:63
std::string directory
Definition httpserver.hpp:69
std::string alias
Definition httpserver.hpp:71
HttpContentType type
Definition httpserver.hpp:68
HttpMethod methods
Definition httpserver.hpp:67
std::function< void(typename Protocol::Worker *)> Handler
Definition httpserver.hpp:64
Handler handler
Definition httpserver.hpp:72
std::function< bool(const std::string &, const std::string &, std::error_code &)> Access
Definition httpserver.hpp:65
std::string name
Definition httpserver.hpp:70
Access access
Definition httpserver.hpp:73
uint16_t port
Definition tcpacceptor_test.cpp:36
std::string path
Definition unixstreamacceptor_test.cpp:34