server.cpp 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #include "kbf/http/server.h"
  2. #include <esp_log.h>
  3. #include <memory>
  4. #include "kbf/macros.h"
  5. using namespace kbf;
  6. http::Server &http::Server::route(http::Server::Route route) {
  7. ESP_LOGD(TAG, "adding route: %s", route.uri.c_str());
  8. routes.push_back(route);
  9. return *this;
  10. }
  11. http::Server &http::Server::start(int port) {
  12. ESP_LOGI(TAG, "starting HTTP server on port %d", port);
  13. if (running) {
  14. ESP_LOGE(TAG, "server already running");
  15. ABORT("fix me");
  16. }
  17. handle = nullptr;
  18. httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  19. config.server_port = port;
  20. config.stack_size = 16384;
  21. CHECK(httpd_start(&handle, &config));
  22. ESP_LOGI(TAG, "registering URI handlers");
  23. for (auto &route : routes) {
  24. ESP_LOGI(TAG, " method: %d; uri: %s", static_cast<int>(route.method), route.uri.c_str());
  25. httpd_uri_t uriHandler = {
  26. .uri = route.uri.c_str(),
  27. .method = static_cast<httpd_method_t>(route.method),
  28. .handler = handleHttpRequest,
  29. .user_ctx = &route
  30. };
  31. CHECK(httpd_register_uri_handler(handle, &uriHandler));
  32. }
  33. running = true;
  34. return *this;
  35. }
  36. void http::Server::stop() {
  37. CHECK(httpd_stop(handle));
  38. running = false;
  39. }
  40. // TODO handle all status codes; also maybe use macro or constexpr or something?
  41. static string getDefaultStatusText(int status) {
  42. if (status == 200) return "OK";
  43. if (status == 204) return "No Content";
  44. if (status == 400) return "Bad Request";
  45. if (status == 500) return "Internal Server Error";
  46. return "Unknown HTTP Status";
  47. }
  48. esp_err_t http::Server::handleHttpRequest(httpd_req_t *httpdRequest) {
  49. auto route = static_cast<Route *>(httpdRequest->user_ctx);
  50. ESP_LOGD(TAG, "incoming request: method %d, path %s", httpdRequest->method, route->uri.c_str());
  51. auto request = Request(httpdRequest);
  52. auto response = route->handler(request);
  53. CHECK(httpd_resp_set_hdr(httpdRequest, "Server", "kbf_http_server/0.1"));
  54. CHECK(httpd_resp_set_type(httpdRequest, response.contentType.c_str()));
  55. for (const auto &[name, value] : response.headers) {
  56. CHECK(httpd_resp_set_hdr(httpdRequest, name.c_str(), value.c_str()));
  57. }
  58. if (response.statusText.empty()) {
  59. response.statusText = getDefaultStatusText(response.status);
  60. }
  61. string status = std::to_string(response.status) + " " + response.statusText;
  62. ESP_LOGD(TAG, "sending response with status: %s", status.c_str());
  63. CHECK(httpd_resp_set_status(httpdRequest, status.c_str()));
  64. CHECK(httpd_resp_send(httpdRequest, response.body.c_str(), response.body.length()));
  65. return ESP_OK;
  66. }
  67. http::Server::~Server() {
  68. if (running) stop();
  69. }