server.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #include "kbf/http/server.h"
  2. #include <esp_log.h>
  3. #include <esp_https_server.h>
  4. #include <memory>
  5. #include "kbf/macros.h"
  6. using namespace kbf;
  7. http::Server &http::Server::route(http::Server::Route route) {
  8. ESP_LOGD(TAG, "adding route: %s", route.uri.c_str());
  9. routes.push_back(route);
  10. return *this;
  11. }
  12. http::Server &http::Server::start(int port) {
  13. ESP_LOGI(TAG, "start(%d)", port);
  14. if (running) {
  15. ESP_LOGE(TAG, "server already running");
  16. ABORT("fix me");
  17. }
  18. handle = nullptr;
  19. httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  20. config.server_port = port;
  21. config.stack_size = 16384; // TODO use Kconfig
  22. CHECK(httpd_start(&handle, &config));
  23. registerUriHandlers();
  24. running = true;
  25. return *this;
  26. }
  27. http::Server &http::Server::startSSL(const unsigned char *cert_start, const unsigned char *cert_end,
  28. const unsigned char *key_start, const unsigned char *key_end,
  29. int port) {
  30. ESP_LOGI(TAG, "%s(%d)", __func__, port);
  31. if (running) {
  32. ESP_LOGE(TAG, "server already running");
  33. ABORT("fix me");
  34. }
  35. handle = nullptr;
  36. httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT();
  37. conf.cacert_pem = cert_start;
  38. conf.cacert_len = cert_end - cert_start;
  39. conf.prvtkey_pem = key_start;
  40. conf.prvtkey_len = key_end - key_start;
  41. conf.httpd.stack_size = 16384; // TODO use Kconfig
  42. CHECK(httpd_ssl_start(&handle, &conf));
  43. registerUriHandlers();
  44. running = true;
  45. return *this;
  46. }
  47. void http::Server::registerUriHandlers() {
  48. ESP_LOGD(TAG, "%s()", __func__);
  49. for (auto &route : routes) {
  50. ESP_LOGI(TAG, " method: %d; uri: %s", static_cast<int>(route.method), route.uri.c_str());
  51. httpd_uri_t uriHandler = {
  52. .uri = route.uri.c_str(),
  53. .method = static_cast<httpd_method_t>(route.method),
  54. .handler = handleHttpRequest,
  55. .user_ctx = &route
  56. };
  57. CHECK(httpd_register_uri_handler(handle, &uriHandler));
  58. }
  59. }
  60. void http::Server::stop() {
  61. ESP_LOGI(TAG, "%s()", __func__);
  62. CHECK(httpd_stop(handle));
  63. running = false;
  64. }
  65. // TODO handle all status codes; also maybe use macro or constexpr or something?
  66. static string getDefaultStatusText(int status) {
  67. if (status == 200) return "OK";
  68. if (status == 204) return "No Content";
  69. if (status == 400) return "Bad Request";
  70. if (status == 500) return "Internal Server Error";
  71. return "Unknown HTTP Status";
  72. }
  73. esp_err_t http::Server::handleHttpRequest(httpd_req_t *httpdRequest) {
  74. auto route = static_cast<Route *>(httpdRequest->user_ctx);
  75. ESP_LOGD(TAG, "%s; method: %d, path: \"%s\"", __func__, httpdRequest->method, route->uri.c_str());
  76. auto request = Request(httpdRequest);
  77. auto response = route->handler(request, route->data);
  78. CHECK(httpd_resp_set_hdr(httpdRequest, "Server", "kbf_http_server/0.1"));
  79. CHECK(httpd_resp_set_type(httpdRequest, response.contentType.c_str()));
  80. for (const auto &[name, value] : response.headers) {
  81. CHECK(httpd_resp_set_hdr(httpdRequest, name.c_str(), value.c_str()));
  82. }
  83. if (response.statusText.empty()) {
  84. response.statusText = getDefaultStatusText(response.status);
  85. }
  86. string status = std::to_string(response.status) + " " + response.statusText;
  87. ESP_LOGD(TAG, "response: %s", status.c_str());
  88. CHECK(httpd_resp_set_status(httpdRequest, status.c_str()));
  89. ESP_LOG_BUFFER_HEXDUMP(TAG, response.body.c_str(), response.body.size(), ESP_LOG_VERBOSE);
  90. auto err = httpd_resp_send(httpdRequest, response.body.c_str(), response.body.length());
  91. if (err == ESP_ERR_HTTPD_RESP_SEND) {
  92. ESP_LOGW(TAG, "send failed; maybe client disconnected?");
  93. return ESP_ERR_HTTPD_RESP_SEND;
  94. }
  95. CHECK(err);
  96. if (route->onResponseSent) route->onResponseSent(response, route->data);
  97. return ESP_OK;
  98. }
  99. http::Server::~Server() {
  100. if (running) stop();
  101. }