web_service.h 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. #ifndef KBF_WEB_SERVICE_H
  2. #define KBF_WEB_SERVICE_H
  3. #include <string>
  4. #include <vector>
  5. #include "kbf/http/server.h"
  6. #include "kbf/macros.h"
  7. namespace kbf {
  8. /**
  9. * @brief Controller-based HTTP server.
  10. */
  11. class WebService {
  12. public:
  13. /** @brief Tag used for logging. */
  14. static const constexpr char *TAG = "WebService";
  15. /**
  16. * @brief Constructor.
  17. */
  18. WebService();
  19. /**
  20. * @brief Destructor.
  21. *
  22. * Will call stop() if running.
  23. */
  24. ~WebService();
  25. /**
  26. * @brief Starts the service.
  27. *
  28. * @note All Controllers must be attached before calling start().
  29. *
  30. * @param port web server port; default is 80
  31. */
  32. void start(int port = 80);
  33. /**
  34. * @brief Starts the service in SSL (HTTPS) mode.
  35. *
  36. * @param cert_start start of the certificate
  37. * @param cert_end end of the certificate
  38. * @param key_start start of the private key
  39. * @param key_end end of the private key
  40. * @param port TCP port, default is 443
  41. */
  42. void startSSL(const unsigned char *cert_start, const unsigned char *cert_end,
  43. const unsigned char *key_start, const unsigned char *key_end,
  44. int port = 443);
  45. /**
  46. * @brief Stops the service.
  47. */
  48. void stop();
  49. class Controller;
  50. /**
  51. * @brief Attaches a Controller to the service.
  52. *
  53. * @tparam T Controller class
  54. */
  55. template<class T>
  56. void controller() {
  57. static_assert(std::is_base_of<Controller, T>::value, "controller(): type must be a Controller");
  58. Controller *controller = new T();
  59. void (*handler)(const http::Response &, void *) = nullptr;
  60. if ((void *) (controller->*(&Controller::onResponseSent)) !=
  61. (void *) (&Controller::onResponseSent)) { // NOLINT
  62. // set handler only if onResponseSent is implemented
  63. handler = Controller::responseSentHandler;
  64. }
  65. auto *arg = new HandlerArg{*this, *controller};
  66. server.route({http::Method::GET, controller->path, handleGet, arg, handler});
  67. server.route({http::Method::POST, controller->path, handlePost, arg, handler});
  68. }
  69. class Middleware;
  70. /**
  71. * @brief Adds a #Middleware to the service.
  72. *
  73. * @tparam T Middleware class
  74. */
  75. template<class T>
  76. void middleware() {
  77. static_assert(std::is_base_of<Middleware, T>::value, "middleware(): type must be a Middleware");
  78. middlewares.push_back(new T());
  79. }
  80. /**
  81. * @brief Continue execution of the middleware pipeline.
  82. *
  83. * @note Should be called from middlewares if you want the pipeline to continue.
  84. *
  85. * @param request
  86. * @return response
  87. */
  88. http::Response next(const http::Request &request);
  89. /**
  90. * @brief Controller for the web service.
  91. *
  92. * Pass derived classes to WebService::controller().
  93. */
  94. class Controller {
  95. friend class WebService;
  96. protected:
  97. /**
  98. * @brief Constructor.
  99. *
  100. * Call from child constructor.
  101. *
  102. * @param path URI to handle
  103. */
  104. explicit Controller(std::string path);
  105. /** @brief URI to handle */
  106. const std::string path;
  107. /**
  108. * @brief Method to run on incoming GET requests.
  109. *
  110. * @param request
  111. * @return HTTP response
  112. */
  113. virtual http::Response get(const http::Request &request) {
  114. return http::Response("method not allowed", 405);
  115. }
  116. /**
  117. * @brief Method to run on incoming POST requests.
  118. *
  119. * @param request
  120. * @return HTTP response
  121. */
  122. virtual http::Response post(const http::Request &request) {
  123. return http::Response("method not allowed", 405);
  124. }
  125. /**
  126. * @brief Called after a response is sent successfully.
  127. *
  128. * @param response
  129. */
  130. virtual void onResponseSent(const http::Response &response) {}
  131. private:
  132. static void responseSentHandler(const http::Response &response, void *data);
  133. };
  134. /**
  135. * @brief Base class for HTTP middlewares.
  136. *
  137. * Pass derived classes to #WebService::middleware().
  138. *
  139. * The #run() method will be called for every request. Implementations should call webService->next() for
  140. * the pipeline to continue.
  141. *
  142. * @note If multiple middlewares are added to a WebService, they will be called in the order they were added.
  143. */
  144. class Middleware {
  145. public:
  146. /**
  147. * @brief Function to run for every request. Should call webService->next() for the pipeline to continue.
  148. *
  149. * @param request incoming request
  150. * @param webService webService instance
  151. * @return response
  152. */
  153. virtual http::Response run(const http::Request &request, WebService &webService) = 0;
  154. };
  155. private:
  156. http::Server server;
  157. bool running = false;
  158. struct HandlerArg {
  159. WebService &webService;
  160. Controller &controller;
  161. };
  162. typedef http::Response (WebService::Controller::*MethodFunction)(const http::Request &request);
  163. MethodFunction currentMethod = nullptr;
  164. Controller *currentController = nullptr;
  165. static http::Response handleGet(const http::Request &request, void *data);
  166. static http::Response handlePost(const http::Request &request, void *data);
  167. http::Response startPipeline(const http::Request &request, HandlerArg *arg);
  168. std::vector<Middleware *> middlewares;
  169. std::optional<std::vector<Middleware *>::iterator>
  170. middlewareIt = std::nullopt;
  171. };
  172. }
  173. #endif //KBF_WEB_SERVICE_H