123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- #include "kbf/http/server.h"
- #include <esp_log.h>
- #include <esp_https_server.h>
- #include <memory>
- #include "kbf/macros.h"
- using namespace kbf;
- http::Server &http::Server::route(http::Server::Route route) {
- ESP_LOGD(TAG, "adding route: %s", route.uri.c_str());
- routes.push_back(route);
- return *this;
- }
- http::Server &http::Server::start(int port) {
- ESP_LOGI(TAG, "start(%d)", port);
- if (running) {
- ESP_LOGE(TAG, "server already running");
- ABORT("fix me");
- }
- handle = nullptr;
- httpd_config_t config = HTTPD_DEFAULT_CONFIG();
- config.server_port = port;
- config.stack_size = 16384;
- CHECK(httpd_start(&handle, &config));
- registerUriHandlers();
- running = true;
- return *this;
- }
- http::Server &http::Server::startSSL(int port) {
- ESP_LOGI(TAG, "startSSL(%d)", port);
- if (running) {
- ESP_LOGE(TAG, "server already running");
- ABORT("fix me");
- }
- handle = nullptr;
- httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT();
- extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start");
- extern const unsigned char cacert_pem_end[] asm("_binary_cacert_pem_end");
- conf.cacert_pem = cacert_pem_start;
- conf.cacert_len = cacert_pem_end - cacert_pem_start;
- extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start");
- extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end");
- conf.prvtkey_pem = prvtkey_pem_start;
- conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;
- CHECK(httpd_ssl_start(&handle, &conf));
- registerUriHandlers();
- running = true;
- return *this;
- }
- void http::Server::registerUriHandlers() {
- ESP_LOGI(TAG, "registering URI handlers");
- for (auto &route : routes) {
- ESP_LOGI(TAG, " method: %d; uri: %s", static_cast<int>(route.method), route.uri.c_str());
- httpd_uri_t uriHandler = {
- .uri = route.uri.c_str(),
- .method = static_cast<httpd_method_t>(route.method),
- .handler = handleHttpRequest,
- .user_ctx = &route
- };
- CHECK(httpd_register_uri_handler(handle, &uriHandler));
- }
- }
- void http::Server::stop() {
- CHECK(httpd_stop(handle));
- running = false;
- }
- // TODO handle all status codes; also maybe use macro or constexpr or something?
- static string getDefaultStatusText(int status) {
- if (status == 200) return "OK";
- if (status == 204) return "No Content";
- if (status == 400) return "Bad Request";
- if (status == 500) return "Internal Server Error";
- return "Unknown HTTP Status";
- }
- esp_err_t http::Server::handleHttpRequest(httpd_req_t *httpdRequest) {
- auto route = static_cast<Route *>(httpdRequest->user_ctx);
- ESP_LOGD(TAG, "handleHttpRequest; method: %d, path: \"%s\"", httpdRequest->method, route->uri.c_str());
- auto request = Request(httpdRequest);
- auto response = route->handler(request, route->data);
- CHECK(httpd_resp_set_hdr(httpdRequest, "Server", "kbf_http_server/0.1"));
- CHECK(httpd_resp_set_type(httpdRequest, response.contentType.c_str()));
- for (const auto &[name, value] : response.headers) {
- CHECK(httpd_resp_set_hdr(httpdRequest, name.c_str(), value.c_str()));
- }
- if (response.statusText.empty()) {
- response.statusText = getDefaultStatusText(response.status);
- }
- string status = std::to_string(response.status) + " " + response.statusText;
- ESP_LOGD(TAG, "response: %s", status.c_str());
- CHECK(httpd_resp_set_status(httpdRequest, status.c_str()));
- ESP_LOG_BUFFER_HEXDUMP(TAG, response.body.c_str(), response.body.size(), ESP_LOG_VERBOSE);
- auto err = httpd_resp_send(httpdRequest, response.body.c_str(), response.body.length());
- if (err == ESP_ERR_HTTPD_RESP_SEND) {
- ESP_LOGW(TAG, "send failed; maybe client disconnected?");
- return ESP_ERR_HTTPD_RESP_SEND;
- }
- CHECK(err);
- return ESP_OK;
- }
- http::Server::~Server() {
- if (running) stop();
- }
|