a simple multithreaded webserver
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
3.4 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. #pragma once
  2. #include <mutex>
  3. #include <string>
  4. #include <unordered_map>
  5. #include <thread>
  6. #include <boost/asio/ip/tcp.hpp>
  7. #include <boost/regex.hpp>
  8. #include <boost/beast/http.hpp>
  9. namespace pEp {
  10. namespace beast = boost::beast;
  11. namespace http = beast::http;
  12. namespace net = boost::asio;
  13. using tcp = boost::asio::ip::tcp;
  14. // class Webserver
  15. //
  16. // when an URL handler is present it is called for each matching URL
  17. // otherwise this server is searching for static files in doc_root
  18. // only registered file types and no subdirectories are served for
  19. // static files
  20. //
  21. // to deliver 404 return nullptr from handler
  22. //
  23. // this server is supporting GET for static files and POST for handlers
  24. class Webserver {
  25. public:
  26. typedef boost::regex url_t;
  27. typedef http::request< http::string_body > request;
  28. typedef http::response< http::string_body > response;
  29. typedef std::function< response(boost::cmatch, const request&) > handler_t;
  30. private:
  31. struct Handling {
  32. boost::regex regex;
  33. handler_t handler;
  34. };
  35. net::io_context _ioc;
  36. tcp::acceptor _acceptor;
  37. std::string _doc_root;
  38. std::unordered_map< std::string, Handling > _urls;
  39. handler_t _generic_handler;
  40. unsigned short _port;
  41. bool _running;
  42. std::mutex _mtx;
  43. std::thread _runner;
  44. public:
  45. // if doc_root is empty, don't deliver arbitrary files.
  46. Webserver(net::ip::address addr, unsigned short port, const std::string& doc_root = "");
  47. Webserver(const Webserver&) = delete;
  48. Webserver& operator=(const Webserver&) = delete;
  49. virtual ~Webserver() = default;
  50. constexpr
  51. int port() const noexcept { return _port; }
  52. void add_url_handler (const std::string& url_regex, handler_t handler);
  53. void remove_url_handler(const std::string& url_regex);
  54. // the generic handler will be called if the URL does not match any registered handlers
  55. void add_generic_url_handler (handler_t handler);
  56. void remove_generic_url_handler();
  57. void run();
  58. void shutdown();
  59. static beast::string_view mime_type(beast::string_view path);
  60. static
  61. response create_status_response(const request& req, http::status status);
  62. static Webserver* probing_port_range(net::ip::address addr,
  63. unsigned short start, unsigned short end, unsigned short&
  64. port, const std::string& doc_root = "");
  65. protected:
  66. static void runner(Webserver *me);
  67. void deliver_status(tcp::socket *socket, const request& req, http::status status);
  68. void deliver_file (tcp::socket *socket, const request& req);
  69. handler_t find_handler(const request& req, boost::cmatch& m);
  70. // called at the beginning of a connection thread. Do nothing by default.
  71. virtual void thread_init() {}
  72. // called at the beginning of a connection thread. Do nothing by default.
  73. virtual void thread_done() {}
  74. // is called by run(), in a separate thread.
  75. void do_session(tcp::socket *socket);
  76. };
  77. };