24#include "http/HttpServer.h"
25#include <lwip/sockets.h>
26#include <lwip/netif.h>
27#include <lwip/ip4_addr.h>
28#include "lwip/stats.h"
39#include "pico/stdlib.h"
50#ifdef HTTP_SERVER_USE_TASK_PER_CLIENT
51#warning "⚠️ HTTP_SERVER_USE_TASK_PER_CLIENT is experimental and not yet production-ready. Use with caution."
79 : port(port), router(router)
89 printf(
"[HttpServer] TLS enabled for HTTPS support\n");
121 printf(
"[HttpServer] Starting %s Server on port %d\n",
132 printf(
"[HttpServer] Failed to initialize listener\n");
141 TRACE(
"[HttpServer] Waiting for client connection...\n");
146 QUIET_PRINTF(
"[HttpServer] Accepted client connection\n");
148 vTaskDelay(pdMS_TO_TICKS(10));
150 QUIET_PRINTF(
"[HttpServer] Client connection handled\n");
152 #if !defined(HTTP_SERVER_USE_TASK_PER_CLIENT)
158 warning(
"[HttpServer] Failed to accept client connection\n");
159 vTaskDelay(pdMS_TO_TICKS(10));
179 if (netif && netif->ip_addr.addr != 0)
183 vTaskDelay(pdMS_TO_TICKS(10));
196 printf(
"[HttpServer] Configuring TLS server with certificate and key\n");
204 printf(
"[HttpServer] Server listening on port %d (%s)\n",
215#ifdef HTTP_SERVER_USE_TASK_PER_CLIENT
220 if (xTaskCreate(
handleClientTask,
"HttpClient", 4096, params, 4, NULL) == pdPASS)
222 TRACE(
"Client task created successfully");
226 TRACE(
"Failed to create client task");
234 TRACE(
"Max concurrent clients reached, closing connection");
247 int64_t
start = to_ms_since_boot(get_absolute_time());
248 int64_t lastActivity =
start;
255 TRACE(
"[HttpServer] Empty HTTP method — client either closed connection or it is Safari trying to reuse closed socket\n");
262 TRACE(
"HttpRequest is multipart: %s\n", (req.
isMultipart() ?
"true" :
"false"));
264 TRACE(
"HttpRequest url: %s\n", req.
getUri().c_str());
270 TRACE(
"HttpRequest query parameter %s : %s\n", param.first.c_str(), param.second.c_str());
275 TRACE(
"HttpRequest form parameter %s : %s\n", param.first.c_str(), param.second.c_str());
280 TRACE(
"HttpRequest cookie %s : %s\n", cookie.first.c_str(), cookie.second.c_str());
285 TRACE(
"HttpRequest body length: %d\n", req.
getBody().length());
289 TRACE(
"HttpRequest headers:\n");
292 TRACE(
"%s : %s\n", headr.first.c_str(), headr.second.c_str());
300 TRACE(
"HttpResponse created\n");
304 TRACE(
"HttpRequest handled: %s\n", ok ?
"true" :
"false");
311 lastActivity = to_ms_since_boot(get_absolute_time());
313 if (req.
getHeader(
"Connection") ==
"close")
315 TRACE(
"[HttpServer] Client requested Connection: close, closing connection\n");
319 if (to_ms_since_boot(get_absolute_time()) - lastActivity > idleTimeoutMs)
321 printf(
"[HttpServer] Idle timeout reached, closing connection\n");
326 int64_t end = to_ms_since_boot(get_absolute_time());
327 TRACE(
"[HttpServer] Client handled in %lld ms\n", end -
start);
331#ifdef HTTP_SERVER_USE_TASK_PER_CLIENT
Macro-based debug trace system with optional SD file logging.
#define TRACE_INIT(MODULE_NAME)
Declare trace usage in a source file for a given module.
#define TRACE(...)
Default trace (INFO level).
Event pub/sub manager for embedded applications using FreeRTOS.
SemaphoreHandle_t clientSemaphore
static constexpr int MAX_CONCURRENT_CLIENTS
Utility functions to send standard JSON responses using nlohmann::json.
General-purpose TCP socket abstraction with optional TLS support for both client and server use.
static constexpr std::uintptr_t getTypeKey()
Forward declaration for potential routing needs.
const std::string & getBody() const
Get the request body (copy).
const std::map< std::string, std::string > & getHeaders() const
Get all request headers.
const std::string & getMethod() const
Get the HTTP method.
const std::unordered_multimap< std::string, std::string > getFormParams()
Get parsed form fields (application/x-www-form-urlencoded).
const std::unordered_multimap< std::string, std::string > getQueryParams()
Get parsed query string parameters.
static HttpRequest receive(Tcp *tcp)
Receive and parse an HTTP request from a socket.
const std::unordered_map< std::string, std::string > getCookies() const
Get all parsed cookies.
size_t getHeaderEnd()
Get the header end offset (used for body parsing).
const std::string & getPath() const
Get the parsed request path (without query string).
const std::string getContentType() const
Get the raw Content-Type string.
const std::string & getQuery() const
Get the parsed query string from the URL.
int getContentLength() const
Get the Content-Length header as integer.
const std::string getBoundary() const
Get the boundary string (for multipart/form-data).
bool isMultipart() const
Check whether the request is multipart/form-data.
std::string getHeader(const std::string &field) const
Get a specific header field (case-insensitive).
const std::string & getUri() const
Get the original URL from the request line.
Represents an HTTP response object.
HttpResponse & setHeader(const std::string &key, const std::string &value)
Alias for set() for custom headers.
HTTP Server that listens for incoming connections and dispatches requests.
bool initNetwork()
Initialize the network stack (wait for DHCP or static IP).
static void startServerTask(void *pvParameters)
Launch the HTTP server task (used by FreeRTOS).
void enableTLS(const std::string &certPem, const std::string &keyPem)
Enable TLS/HTTPS support with certificate and private key.
void handleClient(Tcp *conn)
Accept a client connection and handle it directly (not task-based).
static StackType_t xStack[HTTP_STACK_SIZE]
Stack for static FreeRTOS task.
Tcp * initListener()
Create, bind, and listen on the server.
bool isTLSEnabled() const
Check if TLS is enabled for this server.
int port
Accept client connections in a blocking loop and spawn handlers.
void startHandlingClient(Tcp *conn)
Spawn a task to handle the client connection.
Router & router
Reference to router for dispatching requests.
static void handleClientTask(void *pvParameters)
Handle client logic inside a FreeRTOS task.
HttpServer(int port, Router &router)
Construct a new HttpServer instance.
static StaticTask_t xTaskBuffer
Task control block buffer.
bool start()
Start the HTTP server as a FreeRTOS task.
void run()
Main server loop: initializes, binds, and begins accepting connections.
The central router for handling HTTP requests and middleware.
bool handleRequest(HttpRequest &req, HttpResponse &res)
Handle an incoming HTTP request.
General-purpose TCP socket wrapper with optional TLS support via mbedTLS (altcp).
Tcp * accept()
Accept a new incoming connection (for server use).
void setServerTlsConfig(const std::string &certPem, const std::string &keyPem)
Set the certificate and key to use for server-side TLS (PEM format).
int close()
Close the connection and free resources.
bool bindAndListen(int port)
Bind and listen on a port for incoming connections (for server use).
int getSocketFd() const
Get the raw socket file descriptor (may be -1 for TLS-only connection).
Delegates to user or system configuration.
#define QUIET_PRINTF(...)
#define HTTP_IDLE_TIMEOUT
Timeout for idle HTTP connections in milliseconds.
void sendError(HttpResponse &res, int statusCode, const std::string &code, const std::string &message)
Represents a framework event, optionally carrying payload data.
Parameters passed to the per-client handler task.
Utility functions for URL decoding, form parsing, MIME type lookup, and IP address extraction.
void warning(const std::string &msg)
System utilities for diagnostics, memory, stack usage, and tracing.