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 } while ((this->_max < 0) || (--this->_max != 0));
422
423 this->endRequest ();
424 }
425
431 {
432 // restore concrete stream.
433 this->clearEncoding ();
434
435 // prepare a standard response.
436 this->_response.response ("200", "OK");
437
438 // read request headers.
439 if (this->_request.readHeaders (*this) == -1)
440 {
442 {
443 this->sendError ("400", "Bad Request");
444 }
446 {
447 this->sendError ("405", "Method Not Allowed");
448 }
450 {
451 this->sendError ("494", "Request Header Too Large");
452 }
453 return -1;
454 }
455
456 // check host.
457 if (this->_request.host ().empty ())
458 {
459 this->sendError ("400", "Bad Request");
460 return -1;
461 }
462
463 // set encoding.
464 if (this->_request.hasHeader ("Transfer-Encoding"))
465 {
466 this->setEncoding (join::rsplit (this->_request.header ("Transfer-Encoding"), ","));
467 }
468 if (this->_request.hasHeader ("Content-Encoding"))
469 {
470 this->setEncoding (join::rsplit (this->_request.header ("Content-Encoding"), ","));
471 }
472
473 return 0;
474 }
475
480 {
481 Content* content = this->_server->findContent (this->_request.method (), this->_request.path ());
482 if (content == nullptr)
483 {
484 this->sendError ("404", "Not Found");
485 return;
486 }
487
488 if (content->access != nullptr)
489 {
490 if (!this->_request.hasHeader ("Authorization"))
491 {
492 this->sendError ("401", "Unauthorized");
493 return;
494 }
495
496 std::error_code err;
497 if (!content->access (this->_request.auth (), this->_request.credentials (), err))
498 {
499 if (err == HttpErrc::Unauthorized)
500 {
501 this->sendError ("401", "Unauthorized");
502 }
503 else if (err == HttpErrc::Forbidden)
504 {
505 this->sendError ("403", "Forbidden");
506 }
507 return;
508 }
509 }
510
511 std::string alias (content->alias);
512 if (!alias.empty ())
513 {
514 join::replaceAll (alias, "$root", this->_server->baseLocation ());
515 join::replaceAll (alias, "$scheme", this->_server->scheme ());
516 join::replaceAll (alias, "$host", this->_request.host ());
517 join::replaceAll (alias, "$port", std::to_string (this->localEndpoint ().port ()));
518 join::replaceAll (alias, "$path", this->_request.path ());
519 join::replaceAll (alias, "$query", this->_request.query ());
520 join::replaceAll (alias, "$urn", this->_request.urn ());
521 }
522
523 if (content->type == HttpContentType::Root)
524 {
525 this->sendFile (this->_server->baseLocation () + this->_request.path ());
526 }
527 else if (content->type == HttpContentType::Alias)
528 {
529 this->sendFile (alias);
530 }
531 else if (content->type == HttpContentType::Exec)
532 {
533 if (content->handler == nullptr)
534 {
535 this->sendError ("500", "Internal Server Error");
536 return;
537 }
538 content->handler (this);
539 }
540 else if (content->type == HttpContentType::Redirect)
541 {
542 if (this->_request.version () == "HTTP/1.1")
543 {
544 this->sendRedirect ("307", "Temporary Redirect", alias);
545 }
546 else
547 {
548 this->sendRedirect ("302", "Found", alias);
549 }
550 }
551 }
552
556 void cleanUp ()
557 {
558 this->_request.clear ();
559 this->_response.clear ();
560 }
561
566 {
567 this->disconnect ();
568 this->close ();
569 }
570
575 void setEncoding (const std::vector<std::string>& encodings)
576 {
577 for (auto const& encoding : encodings)
578 {
579 if (encoding.find ("gzip") != std::string::npos)
580 {
581 this->_streambuf = new Zstreambuf (this->_streambuf, Zstream::Gzip, this->_wrapped);
582 this->_wrapped = true;
583 }
584 else if (encoding.find ("deflate") != std::string::npos)
585 {
586 this->_streambuf = new Zstreambuf (this->_streambuf, Zstream::Deflate, this->_wrapped);
587 this->_wrapped = true;
588 }
589 else if (encoding.find ("chunked") != std::string::npos)
590 {
591 this->_streambuf = new Chunkstreambuf (this->_streambuf, this->_wrapped);
592 this->_wrapped = true;
593 }
594 }
595
596 this->set_rdbuf (this->_streambuf);
597 }
598
603 {
604 if (this->_wrapped && this->_streambuf)
605 {
606 delete this->_streambuf;
607 this->_streambuf = nullptr;
608 }
609
610 this->_streambuf = &this->_sockbuf;
611 this->_wrapped = false;
612
613 this->set_rdbuf (this->_streambuf);
614 }
615
617 int _max = 0;
618
621
624
626 std::streambuf* _streambuf = nullptr;
627
629 bool _wrapped = false;
630
633
636 };
637
641 template <class Protocol>
643 {
644 public:
647 using Handler = typename Content::Handler;
648 using Access = typename Content::Access;
649 using Endpoint = typename Protocol::Endpoint;
650 using Socket = typename Protocol::Socket;
651 using Acceptor = typename Protocol::Acceptor;
652
657 BasicHttpServer (size_t workers = std::thread::hardware_concurrency ())
658 : _event (eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC | EFD_SEMAPHORE))
659 , _nworkers (workers)
660 , _baseLocation ("/var/www")
661 , _keepTimeout (10)
662 {
663 [[maybe_unused]] int res = chdir (this->_baseLocation.c_str ());
664 }
665
670 BasicHttpServer (const BasicHttpServer& other) = delete;
671
678
684
691
696 {
697 this->_acceptor.close ();
698 this->_contents.clear ();
699 ::close (this->_event);
700 }
701
707 int create (const Endpoint& endpoint) noexcept
708 {
709 if (this->_acceptor.create (endpoint) == -1)
710 {
711 return -1;
712 }
713
714 for (size_t nworkers = 0; nworkers < this->_nworkers; ++nworkers)
715 {
716 this->_workers.emplace_back (new Worker (this));
717 }
718
719 return 0;
720 }
721
725 void close () noexcept
726 {
727 uint64_t val = this->_nworkers;
728 [[maybe_unused]] ssize_t bytes = ::write (this->_event, &val, sizeof (uint64_t));
729 this->_workers.clear ();
730 this->_acceptor.close ();
731 }
732
737 virtual Socket accept () const
738 {
739 return this->_acceptor.accept ();
740 }
741
746 void baseLocation (const std::string& path)
747 {
748 this->_baseLocation = path;
749
750 if (*this->_baseLocation.rbegin () == '/')
751 {
752 this->_baseLocation.pop_back ();
753 }
754
755 [[maybe_unused]] int res = chdir (this->_baseLocation.c_str ());
756 }
757
762 const std::string& baseLocation () const
763 {
764 return this->_baseLocation;
765 }
766
772 void keepAlive (std::chrono::seconds timeout, int max = 1000)
773 {
774 this->_keepTimeout = timeout;
775 this->_keepMax = max;
776 }
777
782 std::chrono::seconds keepAliveTimeout () const
783 {
784 return this->_keepTimeout;
785 }
786
791 int keepAliveMax () const
792 {
793 return this->_keepMax;
794 }
795
800 virtual std::string scheme () const
801 {
802 return "http";
803 }
804
812 Content* addDocumentRoot (const std::string& dir, const std::string& name, const Access& access = nullptr)
813 {
814 Content* newEntry = new Content;
815 if (newEntry != nullptr)
816 {
817 newEntry->methods = Head | Get;
818 newEntry->type = Root;
819 newEntry->directory = dir;
820 newEntry->name = name;
821 newEntry->handler = nullptr;
822 newEntry->access = access;
823 this->_contents.emplace_back (newEntry);
824 }
825
826 return newEntry;
827 }
828
837 Content* addAlias (const std::string& dir, const std::string& name, const std::string& alias,
838 const Access& access = nullptr)
839 {
840 Content* newEntry = new Content;
841 if (newEntry != nullptr)
842 {
843 newEntry->methods = Head | Get;
844 newEntry->type = Alias;
845 newEntry->directory = dir;
846 newEntry->name = name;
847 newEntry->alias = alias;
848 newEntry->handler = nullptr;
849 newEntry->access = access;
850 this->_contents.emplace_back (newEntry);
851 }
852
853 return newEntry;
854 }
855
865 Content* addExecute (const HttpMethod methods, const std::string& dir, const std::string& name,
866 const Handler& handler, const Access& access = nullptr)
867 {
868 Content* newEntry = new Content;
869 if (newEntry != nullptr)
870 {
871 newEntry->methods = methods;
872 newEntry->type = Exec;
873 newEntry->directory = dir;
874 newEntry->name = name;
875 newEntry->handler = handler;
876 newEntry->access = access;
877 this->_contents.emplace_back (newEntry);
878 }
879
880 return newEntry;
881 }
882
891 Content* addRedirect (const std::string& dir, const std::string& name, const std::string& location,
892 const Access& access = nullptr)
893 {
894 Content* newEntry = new Content;
895 if (newEntry != nullptr)
896 {
897 newEntry->methods = Head | Get | Put | Post | Delete;
898 newEntry->type = Redirect;
899 newEntry->directory = dir;
900 newEntry->name = name;
901 newEntry->alias = location;
902 newEntry->handler = nullptr;
903 newEntry->access = access;
904 this->_contents.emplace_back (newEntry);
905 }
906
907 return newEntry;
908 }
909
910 protected:
917 Content* findContent (HttpMethod method, const std::string& path) const
918 {
919 std::string directory = join::base (path);
920 std::string name = join::filename (path);
921
922 for (auto const& content : this->_contents)
923 {
924 if (content->methods & method)
925 {
926 if (fnmatch (content->directory.c_str (), directory.c_str (), FNM_CASEFOLD) == 0)
927 {
928 if (fnmatch (content->name.c_str (), name.c_str (), FNM_CASEFOLD) == 0)
929 {
930 return content.get ();
931 }
932 }
933 }
934 }
935
936 return nullptr;
937 }
938
941
943 int _event = -1;
944
946 size_t _nworkers;
947
949 std::vector<std::unique_ptr<Worker>> _workers;
950
953
955 std::vector<std::unique_ptr<Content>> _contents;
956
958 std::string _baseLocation;
959
961 std::chrono::seconds _keepTimeout;
962
964 int _keepMax = 1000;
965
968
970 friend Worker;
971 };
972
976 template <class Protocol>
977 class BasicHttpSecureServer : public BasicHttpServer<Protocol>
978 {
979 public:
982 using Handler = typename Content::Handler;
983 using Access = typename Content::Access;
984 using Endpoint = typename Protocol::Endpoint;
985 using Socket = typename Protocol::Socket;
986 using Acceptor = typename Protocol::Acceptor;
987
992 BasicHttpSecureServer (size_t workers = std::thread::hardware_concurrency ())
993 : BasicHttpServer<Protocol> (workers)
994 {
995 }
996
1002
1009
1015
1022
1026 virtual ~BasicHttpSecureServer () = default;
1027
1032 Socket accept () const override
1033 {
1034 return this->_acceptor.acceptEncrypted ();
1035 }
1036
1043 int setCertificate (const std::string& cert, const std::string& key = "")
1044 {
1045 return this->_acceptor.setCertificate (cert, key);
1046 }
1047
1053 int setCaCertificate (const std::string& caFile)
1054 {
1055 return this->_acceptor.setCaCertificate (caFile);
1056 }
1057
1063 void setVerify (bool verify, int depth = -1)
1064 {
1065 return this->_acceptor.setVerify (verify, depth);
1066 }
1067
1073 int setCipher (const std::string& cipher)
1074 {
1075 return this->_acceptor.setCipher (cipher);
1076 }
1077
1083 int setCipher_1_3 (const std::string& cipher)
1084 {
1085 return this->_acceptor.setCipher_1_3 (cipher);
1086 }
1087
1088#if OPENSSL_VERSION_NUMBER >= 0x30000000L
1094 int setCurve (const std::string& curves)
1095 {
1096 return this->_acceptor.setCurve (curves);
1097 }
1098#endif
1099
1104 virtual std::string scheme () const override
1105 {
1106 return "https";
1107 }
1108
1110 friend Worker;
1111 };
1112}
1113
1114#endif
basic HTTPS server.
Definition httpserver.hpp:978
BasicHttpSecureServer(size_t workers=std::thread::hardware_concurrency())
create the HTTPS server instance.
Definition httpserver.hpp:992
typename Protocol::Acceptor Acceptor
Definition httpserver.hpp:986
typename Protocol::Endpoint Endpoint
Definition httpserver.hpp:984
int setCertificate(const std::string &cert, const std::string &key="")
set the certificate and the private key.
Definition httpserver.hpp:1043
typename Content::Handler Handler
Definition httpserver.hpp:982
friend Worker
friendship with worker.
Definition httpserver.hpp:1110
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:1053
typename Protocol::Socket Socket
Definition httpserver.hpp:985
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:1073
Socket accept() const override
accept new connection and fill in the client object with connection parameters.
Definition httpserver.hpp:1032
virtual ~BasicHttpSecureServer()=default
destroy the HTTPS server.
typename Content::Access Access
Definition httpserver.hpp:983
virtual std::string scheme() const override
get scheme.
Definition httpserver.hpp:1104
void setVerify(bool verify, int depth=-1)
Enable/Disable the verification of the peer certificate.
Definition httpserver.hpp:1063
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:1083
basic HTTP server.
Definition httpserver.hpp:643
BasicHttpServer(size_t workers=std::thread::hardware_concurrency())
create the HTTP server instance.
Definition httpserver.hpp:657
typename Content::Handler Handler
Definition httpserver.hpp:647
typename Protocol::Socket Socket
Definition httpserver.hpp:650
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:837
typename Content::Access Access
Definition httpserver.hpp:648
std::vector< std::unique_ptr< Worker > > _workers
workers.
Definition httpserver.hpp:949
std::string _baseLocation
base location.
Definition httpserver.hpp:958
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:865
void keepAlive(std::chrono::seconds timeout, int max=1000)
set HTTP keep alive.
Definition httpserver.hpp:772
const std::string & baseLocation() const
get file base location.
Definition httpserver.hpp:762
typename Protocol::Endpoint Endpoint
Definition httpserver.hpp:649
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:891
Acceptor _acceptor
acceptor.
Definition httpserver.hpp:940
void baseLocation(const std::string &path)
set file base location.
Definition httpserver.hpp:746
int _keepMax
keep alive max.
Definition httpserver.hpp:964
typename Protocol::Acceptor Acceptor
Definition httpserver.hpp:651
virtual Socket accept() const
accept new connection.
Definition httpserver.hpp:737
void close() noexcept
close server.
Definition httpserver.hpp:725
virtual ~BasicHttpServer()
destroy the HTTP server.
Definition httpserver.hpp:695
Content * findContent(HttpMethod method, const std::string &path) const
find content.
Definition httpserver.hpp:917
Cache _cache
file cache.
Definition httpserver.hpp:967
std::vector< std::unique_ptr< Content > > _contents
contents.
Definition httpserver.hpp:955
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:812
friend Worker
friendship with worker.
Definition httpserver.hpp:970
int keepAliveMax() const
get HTTP keep alive max.
Definition httpserver.hpp:791
int _event
gracefully stop all workers.
Definition httpserver.hpp:943
int create(const Endpoint &endpoint) noexcept
create server.
Definition httpserver.hpp:707
BasicHttpContent< Protocol > Content
Definition httpserver.hpp:646
std::chrono::seconds keepAliveTimeout() const
get HTTP keep alive timeout.
Definition httpserver.hpp:782
size_t _nworkers
number of workers.
Definition httpserver.hpp:946
std::chrono::seconds _keepTimeout
keep alive timeout.
Definition httpserver.hpp:961
BasicHttpServer(BasicHttpServer &&other)=delete
create instance by move.
Mutex _mutex
accept protection mutex.
Definition httpserver.hpp:952
BasicHttpServer(const BasicHttpServer &other)=delete
create instance by copy.
virtual std::string scheme() const
get scheme.
Definition httpserver.hpp:800
basic HTTP worker.
Definition httpserver.hpp:81
void setEncoding(const std::vector< std::string > &encodings)
set stream encoding.
Definition httpserver.hpp:575
void clearEncoding()
clear stream encoding.
Definition httpserver.hpp:602
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:626
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:620
void sendHeaders()
send headers.
Definition httpserver.hpp:135
void writeResponse()
write the HTTP response.
Definition httpserver.hpp:479
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:617
BasicHttpWorker(const BasicHttpWorker &other)=delete
create instance by copy.
void cleanUp()
clean all.
Definition httpserver.hpp:556
BasicHttpWorker & operator=(const BasicHttpWorker &other)=delete
assign instance by copy.
bool _wrapped
HTTP stream status.
Definition httpserver.hpp:629
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:565
HttpResponse _response
HTTP response.
Definition httpserver.hpp:623
Server * _server
HTTP server.
Definition httpserver.hpp:632
int readRequest()
read the HTTP request.
Definition httpserver.hpp:430
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:635
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:251
@ 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