join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
httpserver.hpp
Go to the documentation of this file.
1
25#ifndef __JOIN_HTTP_SERVER_HPP__
26#define __JOIN_HTTP_SERVER_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:
83 using Content = BasicHttpContent <Protocol>;
84 using Server = BasicHttpServer <Protocol>;
85
91 : _server (server),
92 _thread ([this] () {work ();})
93 {
94 }
95
100 BasicHttpWorker (const BasicHttpWorker& other) = delete;
101
108
114
121
126 {
127 this->_thread.join ();
128 }
129
134 {
135 // restore concrete stream.
136 this->clearEncoding ();
137
138 // set missing response headers.
139 if (!this->_response.hasHeader ("Date"))
140 {
141 std::stringstream gmt;
142 std::time_t ti = std::time (nullptr);
143 gmt << std::put_time (std::gmtime (&ti), "%a, %d %b %Y %H:%M:%S GMT");
144 this->_response.header ("Date", gmt.str ());
145 }
146 if (!this->_response.hasHeader ("Server"))
147 {
148 this->_response.header ("Server", "join/" JOIN_VERSION);
149 }
150 if (!this->_response.hasHeader ("Connection"))
151 {
152 if (this->_max && compareNoCase (this->_request.header ("Connection"), "keep-alive"))
153 {
154 std::stringstream keepAlive;
155 keepAlive << "timeout=" << this->_server->keepAliveTimeout ().count () << ", max=" << this->_server->keepAliveMax ();
156 this->_response.header ("Keep-Alive", keepAlive.str ());
157 this->_response.header ("Connection", "Keep-Alive");
158 }
159 else
160 {
161 this->_response.header ("Connection", "close");
162 this->_max = 0;
163 }
164 }
165 if (this->encrypted () && !this->_response.hasHeader ("Strict-Transport-Security"))
166 {
167 this->_response.header ("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload");
168 }
169 if (!this->_response.hasHeader ("Content-Security-Policy"))
170 {
171 this->_response.header ("Content-Security-Policy", "default-src 'self'; object-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'");
172 }
173 if (!this->_response.hasHeader ("X-XSS-Protection"))
174 {
175 this->_response.header ("X-XSS-Protection", "1; mode=block");
176 }
177 if (!this->_response.hasHeader ("X-Content-Type-Options"))
178 {
179 this->_response.header ("X-Content-Type-Options", "nosniff");
180 }
181 if (!this->_response.hasHeader ("X-Frame-Options"))
182 {
183 this->_response.header ("X-Frame-Options", "SAMEORIGIN");
184 }
185
186 // write response headers.
187 this->_response.writeHeaders (*this);
188
189 // set encoding.
190 if (this->_response.hasHeader ("Transfer-Encoding"))
191 {
192 this->setEncoding (join::rsplit (this->_response.header ("Transfer-Encoding"), ","));
193 }
194 if (this->_response.hasHeader ("Content-Encoding"))
195 {
196 this->setEncoding (join::rsplit (this->_response.header ("Content-Encoding"), ","));
197 }
198 }
199
205 void sendError (const std::string& status, const std::string& reason)
206 {
207 // set error response.
208 this->_response.response (status, reason);
209
210 // stop keepalive.
211 this->_response.header ("Connection", "close");
212 this->_max = 0;
213
214 // send headers.
215 this->sendHeaders ();
216
217 // flush data.
218 this->flush ();
219 }
220
227 void sendRedirect (const std::string& status, const std::string& reason, const std::string& location = {})
228 {
229 std::string payload;
230
231 // set redirect response.
232 this->_response.response (status, reason);
233
234 // set redirect message payload.
235 if (!location.empty ())
236 {
237 payload += "<html>";
238 payload += "<head>";
239 payload += "<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">";
240 payload += "<title>" + status + " " + reason + "</title>";
241 payload += "</head>";
242 payload += "<body>";
243 payload += "<h1>" + status + " " + reason + "</h1>";
244 payload += "The document has moved <a href=\"" + location + "\">here</a>";
245 payload += "</body>";
246 payload += "</html>";
247 }
248
249 // set content.
250 if (payload.size ())
251 {
252 this->_response.header ("Content-Length", std::to_string (payload.size ()));
253 this->_response.header ("Content-Type", "text/html");
254 this->_response.header ("Cache-Control", "no-cache");
255 }
256
257 // send headers.
258 this->sendHeaders ();
259
260 // send payload.
261 if (payload.size ())
262 {
263 this->write (payload.c_str (), payload.size ());
264 }
265
266 // flush data.
267 this->flush ();
268 }
269
274 void sendFile (const std::string& path)
275 {
276 struct stat sbuf;
277
278 // get file.
279 void* addr = this->_server->_cache.get (path, sbuf);
280 if (addr == nullptr || S_ISDIR (sbuf.st_mode))
281 {
282 this->sendError ("404", "Not Found");
283 return;
284 }
285
286 // check modif time.
287 std::stringstream modifTime;
288 modifTime << std::put_time (std::gmtime (&sbuf.st_ctime), "%a, %d %b %Y %H:%M:%S GMT");
289 if (compareNoCase (this->_request.header ("If-Modified-Since"), modifTime.str ()))
290 {
291 this->sendRedirect ("304", "Not Modified");
292 return;
293 }
294
295 // set modif time.
296 this->_response.header ("Last-Modified", modifTime.str ());
297
298 // set content.
299 this->_response.header ("Content-Length", std::to_string (sbuf.st_size));
300 this->_response.header ("Content-Type", join::mime (path));
301 this->_response.header ("Cache-Control", "no-cache");
302
303 // send headers.
304 this->sendHeaders ();
305
306 // check method.
307 if (this->_request.method () == HttpMethod::Get)
308 {
309 // send file.
310 this->write (static_cast <char *> (addr), sbuf.st_size);
311 }
312
313 // flush data.
314 this->flush ();
315 }
316
322 bool hasHeader (const std::string& name) const
323 {
324 return this->_request.hasHeader (name);
325 }
326
332 std::string header (const std::string& name) const
333 {
334 return this->_request.header (name);
335 }
336
341 size_t contentLength () const
342 {
343 return this->_request.contentLength ();
344 }
345
351 void header (const std::string& name, const std::string& val)
352 {
353 return this->_response.header (name, val);
354 }
355
356 protected:
360 void work ()
361 {
362 fd_set setfd;
363 FD_ZERO (&setfd);
364 int fdmax = -1;
365
366 FD_SET (this->_server->_event, &setfd);
367 fdmax = std::max (fdmax, this->_server->_event);
368 FD_SET (this->_server->_acceptor.handle (), &setfd);
369 fdmax = std::max (fdmax, this->_server->_acceptor.handle ());
370
371 for (;;)
372 {
373 {
374 ScopedLock <Mutex> lock (this->_server->_mutex);
375
376 fd_set fdset = setfd;
377 int nset = ::select (fdmax + 1, &fdset, nullptr, nullptr, nullptr);
378 if (nset > 0)
379 {
380 if (FD_ISSET (this->_server->_event, &fdset))
381 {
382 uint64_t val = 0;
383 [[maybe_unused]] ssize_t bytes = ::read (this->_server->_event, &val, sizeof (uint64_t));
384 return;
385 }
386
387 if (FD_ISSET (this->_server->_acceptor.handle (), &fdset))
388 {
389 this->_sockbuf.socket () = this->_server->accept ();
390 this->_sockbuf.timeout (this->_server->keepAliveTimeout ().count () * 1000);
391 }
392 }
393 }
394
395 this->processRequest ();
396 }
397 }
398
403 {
404 this->_max = this->_server->keepAliveMax ();
405
406 do
407 {
408 if (this->readRequest () == -1)
409 {
410 this->cleanUp ();
411 break;
412 }
413
414 this->writeResponse ();
415 this->cleanUp ();
416 }
417 while ((this->_max < 0) || (--this->_max != 0));
418
419 this->endRequest ();
420 }
421
427 {
428 // restore concrete stream.
429 this->clearEncoding ();
430
431 // prepare a standard response.
432 this->_response.response ("200", "OK");
433
434 // read request headers.
435 if (this->_request.readHeaders (*this) == -1)
436 {
438 {
439 this->sendError ("400", "Bad Request");
440 }
442 {
443 this->sendError ("405", "Method Not Allowed");
444 }
446 {
447 this->sendError ("494", "Request Header Too Large");
448 }
449 return -1;
450 }
451
452 // check host.
453 if (this->_request.host ().empty ())
454 {
455 this->sendError ("400", "Bad Request");
456 return -1;
457 }
458
459 // set encoding.
460 if (this->_request.hasHeader ("Transfer-Encoding"))
461 {
462 this->setEncoding (join::rsplit (this->_request.header ("Transfer-Encoding"), ","));
463 }
464 if (this->_request.hasHeader ("Content-Encoding"))
465 {
466 this->setEncoding (join::rsplit (this->_request.header ("Content-Encoding"), ","));
467 }
468
469 return 0;
470 }
471
476 {
477 Content* content = this->_server->findContent (this->_request.method (), this->_request.path ());
478 if (content == nullptr)
479 {
480 this->sendError ("404", "Not Found");
481 return;
482 }
483
484 if (content->access != nullptr)
485 {
486 if (!this->_request.hasHeader ("Authorization"))
487 {
488 this->sendError ("401", "Unauthorized");
489 return;
490 }
491
492 std::error_code err;
493 if (!content->access (this->_request.auth (), this->_request.credentials (), err))
494 {
495 if (err == HttpErrc::Unauthorized)
496 {
497 this->sendError ("401", "Unauthorized");
498 }
499 else if (err == HttpErrc::Forbidden)
500 {
501 this->sendError ("403", "Forbidden");
502 }
503 return;
504 }
505 }
506
507 std::string alias (content->alias);
508 if (!alias.empty ())
509 {
510 join::replaceAll (alias, "$root", this->_server->baseLocation ());
511 join::replaceAll (alias, "$scheme", this->_server->scheme ());
512 join::replaceAll (alias, "$host", this->_request.host ());
513 join::replaceAll (alias, "$port", std::to_string (this->localEndpoint ().port ()));
514 join::replaceAll (alias, "$path", this->_request.path ());
515 join::replaceAll (alias, "$query", this->_request.query ());
516 join::replaceAll (alias, "$urn", this->_request.urn ());
517 }
518
519 if (content->type == HttpContentType::Root)
520 {
521 this->sendFile (this->_server->baseLocation () + this->_request.path ());
522 }
523 else if (content->type == HttpContentType::Alias)
524 {
525 this->sendFile (alias);
526 }
527 else if (content->type == HttpContentType::Exec)
528 {
529 if (content->handler == nullptr)
530 {
531 this->sendError ("500", "Internal Server Error");
532 return;
533 }
534 content->handler (this);
535 }
536 else if (content->type == HttpContentType::Redirect)
537 {
538 if (this->_request.version () == "HTTP/1.1")
539 {
540 this->sendRedirect ("307", "Temporary Redirect", alias);
541 }
542 else
543 {
544 this->sendRedirect ("302", "Found", alias);
545 }
546 }
547 }
548
552 void cleanUp ()
553 {
554 this->_request.clear ();
555 this->_response.clear ();
556 }
557
562 {
563 this->disconnect ();
564 this->close ();
565 }
566
571 void setEncoding (const std::vector <std::string>& encodings)
572 {
573 for (auto const& encoding : encodings)
574 {
575 if (encoding.find ("gzip") != std::string::npos)
576 {
577 this->_streambuf = new Zstreambuf (this->_streambuf, Zstream::Gzip, this->_wrapped);
578 this->_wrapped = true;
579 }
580 else if (encoding.find ("deflate") != std::string::npos)
581 {
582 this->_streambuf = new Zstreambuf (this->_streambuf, Zstream::Deflate, this->_wrapped);
583 this->_wrapped = true;
584 }
585 else if (encoding.find ("chunked") != std::string::npos)
586 {
587 this->_streambuf = new Chunkstreambuf (this->_streambuf, this->_wrapped);
588 this->_wrapped = true;
589 }
590 }
591
592 this->set_rdbuf (this->_streambuf);
593 }
594
599 {
600 if (this->_wrapped && this->_streambuf)
601 {
602 delete this->_streambuf;
603 this->_streambuf = nullptr;
604 }
605
606 this->_streambuf = &this->_sockbuf;
607 this->_wrapped = false;
608
609 this->set_rdbuf (this->_streambuf);
610 }
611
613 int _max = 0;
614
617
620
622 std::streambuf* _streambuf = nullptr;
623
625 bool _wrapped = false;
626
629
632 };
633
637 template <class Protocol>
639 {
640 public:
641 using Worker = BasicHttpWorker <Protocol>;
642 using Content = BasicHttpContent <Protocol>;
643 using Handler = typename Content::Handler;
644 using Access = typename Content::Access;
645 using Endpoint = typename Protocol::Endpoint;
646 using Socket = typename Protocol::Socket;
647 using Acceptor = typename Protocol::Acceptor;
648
653 BasicHttpServer (size_t workers = std::thread::hardware_concurrency ())
654 : _event (eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC | EFD_SEMAPHORE)),
655 _nworkers (workers),
656 _baseLocation ("/var/www"),
657 _keepTimeout (10)
658 {
659 [[maybe_unused]] int res = chdir (this->_baseLocation.c_str ());
660 }
661
666 BasicHttpServer (const BasicHttpServer& other) = delete;
667
674
680
687
692 {
693 this->_acceptor.close ();
694 this->_contents.clear ();
695 ::close (this->_event);
696 }
697
703 int create (const Endpoint& endpoint) noexcept
704 {
705 if (this->_acceptor.create (endpoint) == -1)
706 {
707 return -1;
708 }
709
710 for (size_t nworkers = 0; nworkers < this->_nworkers; ++nworkers)
711 {
712 this->_workers.emplace_back (new Worker (this));
713 }
714
715 return 0;
716 }
717
721 void close () noexcept
722 {
723 uint64_t val = this->_nworkers;
724 [[maybe_unused]] ssize_t bytes = ::write (this->_event, &val, sizeof (uint64_t));
725 this->_workers.clear ();
726 this->_acceptor.close ();
727 }
728
733 virtual Socket accept () const
734 {
735 return this->_acceptor.accept ();
736 }
737
742 void baseLocation (const std::string& path)
743 {
744 this->_baseLocation = path;
745
746 if (*this->_baseLocation.rbegin () == '/')
747 {
748 this->_baseLocation.pop_back ();
749 }
750
751 [[maybe_unused]] int res = chdir (this->_baseLocation.c_str ());
752 }
753
758 const std::string& baseLocation () const
759 {
760 return this->_baseLocation;
761 }
762
768 void keepAlive (std::chrono::seconds timeout, int max = 1000)
769 {
770 this->_keepTimeout = timeout;
771 this->_keepMax = max;
772 }
773
778 std::chrono::seconds keepAliveTimeout () const
779 {
780 return this->_keepTimeout;
781 }
782
787 int keepAliveMax () const
788 {
789 return this->_keepMax;
790 }
791
796 virtual std::string scheme () const
797 {
798 return "http";
799 }
800
808 Content* addDocumentRoot (const std::string& dir, const std::string& name, const Access& access = nullptr)
809 {
810 Content* newEntry = new Content;
811 if (newEntry != nullptr)
812 {
813 newEntry->methods = Head | Get;
814 newEntry->type = Root;
815 newEntry->directory = dir;
816 newEntry->name = name;
817 newEntry->handler = nullptr;
818 newEntry->access = access;
819 this->_contents.emplace_back (newEntry);
820 }
821
822 return newEntry;
823 }
824
833 Content* addAlias (const std::string& dir, const std::string& name, const std::string& alias, const Access& access = nullptr)
834 {
835 Content* newEntry = new Content;
836 if (newEntry != nullptr)
837 {
838 newEntry->methods = Head | Get;
839 newEntry->type = Alias;
840 newEntry->directory = dir;
841 newEntry->name = name;
842 newEntry->alias = alias;
843 newEntry->handler = nullptr;
844 newEntry->access = access;
845 this->_contents.emplace_back (newEntry);
846 }
847
848 return newEntry;
849 }
850
860 Content* addExecute (const HttpMethod methods, const std::string& dir, const std::string& name, const Handler& handler, const Access& access = nullptr)
861 {
862 Content* newEntry = new Content;
863 if (newEntry != nullptr)
864 {
865 newEntry->methods = methods;
866 newEntry->type = Exec;
867 newEntry->directory = dir;
868 newEntry->name = name;
869 newEntry->handler = handler;
870 newEntry->access = access;
871 this->_contents.emplace_back (newEntry);
872 }
873
874 return newEntry;
875 }
876
885 Content* addRedirect (const std::string& dir, const std::string& name, const std::string& location, const Access& access = nullptr)
886 {
887 Content* newEntry = new Content;
888 if (newEntry != nullptr)
889 {
890 newEntry->methods = Head | Get | Put | Post | Delete;
891 newEntry->type = Redirect;
892 newEntry->directory = dir;
893 newEntry->name = name;
894 newEntry->alias = location;
895 newEntry->handler = nullptr;
896 newEntry->access = access;
897 this->_contents.emplace_back (newEntry);
898 }
899
900 return newEntry;
901 }
902
903 protected:
910 Content* findContent (HttpMethod method, const std::string& path) const
911 {
912 std::string directory = join::base (path);
913 std::string name = join::filename (path);
914
915 for (auto const& content : this->_contents)
916 {
917 if (content->methods & method)
918 {
919 if (fnmatch (content->directory.c_str (), directory.c_str (), FNM_CASEFOLD) == 0)
920 {
921 if (fnmatch (content->name.c_str (), name.c_str (), FNM_CASEFOLD) == 0)
922 {
923 return content.get ();
924 }
925 }
926 }
927 }
928
929 return nullptr;
930 }
931
934
936 int _event = -1;
937
939 size_t _nworkers;
940
942 std::vector <std::unique_ptr <Worker>> _workers;
943
946
948 std::vector <std::unique_ptr <Content>> _contents;
949
951 std::string _baseLocation;
952
954 std::chrono::seconds _keepTimeout;
955
957 int _keepMax = 1000;
958
961
963 friend Worker;
964 };
965
969 template <class Protocol>
970 class BasicHttpSecureServer : public BasicHttpServer <Protocol>
971 {
972 public:
973 using Worker = BasicHttpWorker <Protocol>;
974 using Content = BasicHttpContent <Protocol>;
975 using Handler = typename Content::Handler;
976 using Access = typename Content::Access;
977 using Endpoint = typename Protocol::Endpoint;
978 using Socket = typename Protocol::Socket;
979 using Acceptor = typename Protocol::Acceptor;
980
985 BasicHttpSecureServer (size_t workers = std::thread::hardware_concurrency ())
986 : BasicHttpServer <Protocol> (workers)
987 {
988 }
989
995
1002
1008
1015
1019 virtual ~BasicHttpSecureServer () = default;
1020
1025 Socket accept () const override
1026 {
1027 return this->_acceptor.acceptEncrypted ();
1028 }
1029
1036 int setCertificate (const std::string& cert, const std::string& key = "")
1037 {
1038 return this->_acceptor.setCertificate (cert, key);
1039 }
1040
1046 int setCaCertificate (const std::string& caFile)
1047 {
1048 return this->_acceptor.setCaCertificate (caFile);
1049 }
1050
1056 void setVerify (bool verify, int depth = -1)
1057 {
1058 return this->_acceptor.setVerify (verify, depth);
1059 }
1060
1066 int setCipher (const std::string& cipher)
1067 {
1068 return this->_acceptor.setCipher (cipher);
1069 }
1070
1076 int setCipher_1_3 (const std::string &cipher)
1077 {
1078 return this->_acceptor.setCipher_1_3 (cipher);
1079 }
1080
1081#if OPENSSL_VERSION_NUMBER >= 0x30000000L
1087 int setCurve (const std::string &curves)
1088 {
1089 return this->_acceptor.setCurve (curves);
1090 }
1091#endif
1092
1097 virtual std::string scheme () const override
1098 {
1099 return "https";
1100 }
1101
1103 friend Worker;
1104 };
1105}
1106
1107#endif
basic HTTPS server.
Definition httpserver.hpp:971
BasicHttpSecureServer(size_t workers=std::thread::hardware_concurrency())
create the HTTPS server instance.
Definition httpserver.hpp:985
typename Protocol::Acceptor Acceptor
Definition httpserver.hpp:979
typename Protocol::Endpoint Endpoint
Definition httpserver.hpp:977
int setCertificate(const std::string &cert, const std::string &key="")
set the certificate and the private key.
Definition httpserver.hpp:1036
typename Content::Handler Handler
Definition httpserver.hpp:975
friend Worker
friendship with worker.
Definition httpserver.hpp:1103
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:1046
typename Protocol::Socket Socket
Definition httpserver.hpp:978
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:1066
Socket accept() const override
accept new connection and fill in the client object with connection parameters.
Definition httpserver.hpp:1025
virtual ~BasicHttpSecureServer()=default
destroy the HTTPS server.
typename Content::Access Access
Definition httpserver.hpp:976
virtual std::string scheme() const override
get scheme.
Definition httpserver.hpp:1097
void setVerify(bool verify, int depth=-1)
Enable/Disable the verification of the peer certificate.
Definition httpserver.hpp:1056
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:1076
basic HTTP server.
Definition httpserver.hpp:639
BasicHttpServer(size_t workers=std::thread::hardware_concurrency())
create the HTTP server instance.
Definition httpserver.hpp:653
typename Content::Handler Handler
Definition httpserver.hpp:643
typename Protocol::Socket Socket
Definition httpserver.hpp:646
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:833
typename Content::Access Access
Definition httpserver.hpp:644
std::string _baseLocation
base location.
Definition httpserver.hpp:951
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:860
void keepAlive(std::chrono::seconds timeout, int max=1000)
set HTTP keep alive.
Definition httpserver.hpp:768
BasicHttpContent< Protocol > Content
Definition httpserver.hpp:642
const std::string & baseLocation() const
get file base location.
Definition httpserver.hpp:758
typename Protocol::Endpoint Endpoint
Definition httpserver.hpp:645
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:885
Acceptor _acceptor
acceptor.
Definition httpserver.hpp:933
void baseLocation(const std::string &path)
set file base location.
Definition httpserver.hpp:742
int _keepMax
keep alive max.
Definition httpserver.hpp:957
typename Protocol::Acceptor Acceptor
Definition httpserver.hpp:647
virtual Socket accept() const
accept new connection.
Definition httpserver.hpp:733
void close() noexcept
close server.
Definition httpserver.hpp:721
virtual ~BasicHttpServer()
destroy the HTTP server.
Definition httpserver.hpp:691
Content * findContent(HttpMethod method, const std::string &path) const
find content.
Definition httpserver.hpp:910
Cache _cache
file cache.
Definition httpserver.hpp:960
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:808
friend Worker
friendship with worker.
Definition httpserver.hpp:963
int keepAliveMax() const
get HTTP keep alive max.
Definition httpserver.hpp:787
int _event
gracefully stop all workers.
Definition httpserver.hpp:936
int create(const Endpoint &endpoint) noexcept
create server.
Definition httpserver.hpp:703
std::vector< std::unique_ptr< Content > > _contents
contents.
Definition httpserver.hpp:948
std::chrono::seconds keepAliveTimeout() const
get HTTP keep alive timeout.
Definition httpserver.hpp:778
std::vector< std::unique_ptr< Worker > > _workers
workers.
Definition httpserver.hpp:942
size_t _nworkers
number of workers.
Definition httpserver.hpp:939
std::chrono::seconds _keepTimeout
keep alive timeout.
Definition httpserver.hpp:954
BasicHttpServer(BasicHttpServer &&other)=delete
create instance by move.
Mutex _mutex
accept protection mutex.
Definition httpserver.hpp:945
BasicHttpServer(const BasicHttpServer &other)=delete
create instance by copy.
virtual std::string scheme() const
get scheme.
Definition httpserver.hpp:796
basic HTTP worker.
Definition httpserver.hpp:81
void setEncoding(const std::vector< std::string > &encodings)
set stream encoding.
Definition httpserver.hpp:571
void clearEncoding()
clear stream encoding.
Definition httpserver.hpp:598
std::string header(const std::string &name) const
get HTTP request header by name.
Definition httpserver.hpp:332
std::streambuf * _streambuf
HTTP stream buffer.
Definition httpserver.hpp:622
bool hasHeader(const std::string &name) const
checks if there is a HTTP request header with the specified name.
Definition httpserver.hpp:322
BasicHttpWorker(BasicHttpWorker &&other)=delete
create instance by move.
HttpRequest _request
HTTP request.
Definition httpserver.hpp:616
void sendHeaders()
send headers.
Definition httpserver.hpp:133
void writeResponse()
write the HTTP response.
Definition httpserver.hpp:475
void sendFile(const std::string &path)
send a file.
Definition httpserver.hpp:274
void header(const std::string &name, const std::string &val)
add header to the HTTP response.
Definition httpserver.hpp:351
int _max
max requests.
Definition httpserver.hpp:613
BasicHttpWorker(const BasicHttpWorker &other)=delete
create instance by copy.
void cleanUp()
clean all.
Definition httpserver.hpp:552
BasicHttpWorker & operator=(const BasicHttpWorker &other)=delete
assign instance by copy.
bool _wrapped
HTTP stream status.
Definition httpserver.hpp:625
void sendRedirect(const std::string &status, const std::string &reason, const std::string &location={})
send redirect message.
Definition httpserver.hpp:227
void endRequest()
end the HTTP request.
Definition httpserver.hpp:561
HttpResponse _response
HTTP response.
Definition httpserver.hpp:619
Server * _server
HTTP server.
Definition httpserver.hpp:628
int readRequest()
read the HTTP request.
Definition httpserver.hpp:426
void processRequest()
process the HTTP request.
Definition httpserver.hpp:402
virtual ~BasicHttpWorker()
destroy worker thread.
Definition httpserver.hpp:125
Thread _thread
thread.
Definition httpserver.hpp:631
void sendError(const std::string &status, const std::string &reason)
send error message.
Definition httpserver.hpp:205
void work()
worker thread routine.
Definition httpserver.hpp:360
size_t contentLength() const
get content length.
Definition httpserver.hpp:341
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:338
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:544
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
thread class.
Definition thread.hpp:138
void join()
block the current thread until the running thread finishes its execution.
Definition thread.cpp:123
@ 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:117
@ Head
Definition httpmessage.hpp:113
@ Get
Definition httpmessage.hpp:114
__inline__ std::string filename(const std::string &filepath)
get file name of the specified file.
Definition filesystem.hpp:53
__inline__ std::string & replaceAll(std::string &str, const std::string &toReplace, const std::string &by)
replace all occurrences of a substring.
Definition utils.hpp:231
__inline__ 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:274
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
__inline__ bool compareNoCase(const std::string &a, const std::string &b)
case insensitive string comparison.
Definition utils.hpp:188
thread_local std::error_code lastError
last error.
Definition error.cpp:32
__inline__ std::string mime(const std::string &filepath)
get mime type of the specified file.
Definition filesystem.hpp:83
__inline__ std::string base(const std::string &filepath)
get base path of the specified file.
Definition filesystem.hpp:38
basic HTTP content.
Definition httpserver.hpp:63
std::string directory
Definition httpserver.hpp:69
std::function< bool(const std::string &, const std::string &, std::error_code &)> Access
Definition httpserver.hpp:65
std::string alias
Definition httpserver.hpp:71
HttpContentType type
Definition httpserver.hpp:68
HttpMethod methods
Definition httpserver.hpp:67
Handler handler
Definition httpserver.hpp:72
std::function< void(typename Protocol::Worker *)> Handler
Definition httpserver.hpp:64
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