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)
106 printf(
"[HttpServer] Starting HTTP Server on port %d\n",
port);
116 printf(
"[HttpServer] Failed to initialize listener\n");
125 TRACE(
"[HttpServer] Waiting for client connection...\n");
130 QUIET_PRINTF(
"[HttpServer] Accepted client connection\n");
132 vTaskDelay(pdMS_TO_TICKS(10));
134 QUIET_PRINTF(
"[HttpServer] Client connection handled\n");
136 #if !defined(HTTP_SERVER_USE_TASK_PER_CLIENT)
142 warning(
"[HttpServer] Failed to accept client connection\n");
143 vTaskDelay(pdMS_TO_TICKS(10));
163 if (netif && netif->ip_addr.addr != 0)
167 vTaskDelay(pdMS_TO_TICKS(10));
189#ifdef HTTP_SERVER_USE_TASK_PER_CLIENT
194 if (xTaskCreate(
handleClientTask,
"HttpClient", 4096, params, 4, NULL) == pdPASS)
196 TRACE(
"Client task created successfully");
200 TRACE(
"Failed to create client task");
208 TRACE(
"Max concurrent clients reached, closing connection");
221 int64_t
start = to_ms_since_boot(get_absolute_time());
222 int64_t lastActivity =
start;
229 TRACE(
"[HttpServer] Empty HTTP method — client either closed connection or it is Safari trying to reuse closed socket\n");
236 TRACE(
"HttpRequest is multipart: %s\n", (req.
isMultipart() ?
"true" :
"false"));
238 TRACE(
"HttpRequest url: %s\n", req.
getUri().c_str());
244 TRACE(
"HttpRequest query parameter %s : %s\n", param.first.c_str(), param.second.c_str());
249 TRACE(
"HttpRequest form parameter %s : %s\n", param.first.c_str(), param.second.c_str());
254 TRACE(
"HttpRequest cookie %s : %s\n", cookie.first.c_str(), cookie.second.c_str());
259 TRACE(
"HttpRequest body length: %d\n", req.
getBody().length());
263 TRACE(
"HttpRequest headers:\n");
266 TRACE(
"%s : %s\n", headr.first.c_str(), headr.second.c_str());
274 TRACE(
"HttpResponse created\n");
278 TRACE(
"HttpRequest handled: %s\n", ok ?
"true" :
"false");
285 lastActivity = to_ms_since_boot(get_absolute_time());
287 if (req.
getHeader(
"Connection") ==
"close")
289 TRACE(
"[HttpServer] Client requested Connection: close, closing connection\n");
293 if (to_ms_since_boot(get_absolute_time()) - lastActivity > idleTimeoutMs)
295 printf(
"[HttpServer] Idle timeout reached, closing connection\n");
300 int64_t end = to_ms_since_boot(get_absolute_time());
301 TRACE(
"[HttpServer] Client handled in %lld ms\n", end -
start);
305#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 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.
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).
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.