Logo Pico-Framework A web-first embedded framework for C++
Loading...
Searching...
No Matches
HttpServer Class Reference

HTTP Server that listens for incoming connections and dispatches requests. More...

#include <HttpServer.h>

+ Collaboration diagram for HttpServer:

Public Member Functions

 HttpServer (int port, Router &router)
 Construct a new HttpServer instance.
 
bool start ()
 Start the HTTP server as a FreeRTOS task.
 
bool initNetwork ()
 Initialize the network stack (wait for DHCP or static IP).
 
void run ()
 Main server loop: initializes, binds, and begins accepting connections.
 
TcpinitListener ()
 Create, bind, and listen on the server.
 
void handleClient (Tcp *conn)
 Accept a client connection and handle it directly (not task-based).
 
void startHandlingClient (Tcp *conn)
 Spawn a task to handle the client connection.
 
HttpRequest receiveRequest (Tcp *conn, char *method, char *path, std::string &body, size_t &contentLength, std::unordered_map< std::string, std::string > &headers)
 Receive an HTTP request and parse key components.
 
RoutergetRouter ()
 Return the router associated with the server.
 

Static Public Member Functions

static void startServerTask (void *pvParameters)
 Launch the HTTP server task (used by FreeRTOS).
 
static void handleClientTask (void *pvParameters)
 Handle client logic inside a FreeRTOS task.
 

Private Attributes

int port
 Accept client connections in a blocking loop and spawn handlers.
 
Routerrouter
 Reference to router for dispatching requests.
 
Tcp listener
 

Static Private Attributes

static constexpr int BUFFER_SIZE = 1460
 
static constexpr int BOUNDARY_MAX_LEN = 128
 
static StackType_t xStack [HTTP_STACK_SIZE]
 Stack for static FreeRTOS task.
 
static StaticTask_t xTaskBuffer
 Task control block buffer.
 

Detailed Description

Definition at line 28 of file HttpServer.h.

Constructor & Destructor Documentation

◆ HttpServer()

HttpServer::HttpServer ( int  port,
Router router 
)

Construct a new HttpServer instance.

Parameters
portPort number to listen on.
routerReference to the Router for handling requests.
Parameters
portPort number to listen on.
routerReference to the Router for handling requests.

Definition at line 78 of file HttpServer.cpp.

80{
81}
int port
Accept client connections in a blocking loop and spawn handlers.
Definition HttpServer.h:110
Router & router
Reference to router for dispatching requests.
Definition HttpServer.h:111

Member Function Documentation

◆ getRouter()

Router & HttpServer::getRouter ( )
inline
Returns
Router reference.

Definition at line 96 of file HttpServer.h.

96{ return router; }

References router.

◆ handleClient()

void HttpServer::handleClient ( Tcp conn)

Accept a client connection and handle it directly (not task-based).

Tcp* TCP connection instance

Tcp* TCP connection instance

Definition at line 219 of file HttpServer.cpp.

220{
221 int64_t start = to_ms_since_boot(get_absolute_time());
222 int64_t lastActivity = start;
223 const int64_t idleTimeoutMs = HTTP_IDLE_TIMEOUT; // idle timeout - kill connection if no data received
224
225
227 if (req.getMethod().empty())
228 {
229 TRACE("[HttpServer] Empty HTTP method — client either closed connection or it is Safari trying to reuse closed socket\n");
230 return;
231 }
232 TRACE("HttpRequest received: %s, %s\n", req.getMethod().c_str(), req.getPath().c_str());
233 TRACE("HttpRequest content length: %s\n", req.getContentLength());
234 TRACE("HttpRequest content type: %s\n", req.getContentType());
235 TRACE("HttpRequest boundary: %s\n", req.getBoundary());
236 TRACE("HttpRequest is multipart: %s\n", (req.isMultipart() ? "true" : "false"));
237 TRACE("HttpRequest header count: %d\n", req.getHeaders().size());
238 TRACE("HttpRequest url: %s\n", req.getUri().c_str());
239 TRACE("HttpRequest path: %s\n", req.getPath().c_str());
240 TRACE("HttpRequest query: %s\n", req.getQuery().c_str());
241
242 for (const auto& param : req.getQueryParams())
243 {
244 TRACE("HttpRequest query parameter %s : %s\n", param.first.c_str(), param.second.c_str());
245 }
246
247 for (const auto& param : req.getFormParams())
248 {
249 TRACE("HttpRequest form parameter %s : %s\n", param.first.c_str(), param.second.c_str());
250 }
251
252 for (const auto& cookie : req.getCookies())
253 {
254 TRACE("HttpRequest cookie %s : %s\n", cookie.first.c_str(), cookie.second.c_str());
255 }
256
257 if (req.getContentLength() > 0)
258 {
259 TRACE("HttpRequest body length: %d\n", req.getBody().length());
260 TRACE("HttpRequest start of body index: %d\n", req.getHeaderEnd());
261 }
262
263 TRACE("HttpRequest headers:\n");
264 for (const auto& headr : req.getHeaders())
265 {
266 TRACE("%s : %s\n", headr.first.c_str(), headr.second.c_str());
267 }
268
269 TRACE("HttpRequest body: %s\n", req.getBody().c_str());
270
271 QUIET_PRINTF("[HttpServer] Client request received: %s, path: %s\n", req.getMethod().c_str(), req.getPath().c_str());
272
273 HttpResponse res(conn);
274 TRACE("HttpResponse created\n");
275 res.setHeader("Connection", "close"); // Close the connection
276
277 bool ok = router.handleRequest(req, res);
278 TRACE("HttpRequest handled: %s\n", ok ? "true" : "false");
279
280 if (!ok)
281 {
282 JsonResponse::sendError(res, 404, "NOT_FOUND", "route: " + std::string(req.getUri()));
283 }
284
285 lastActivity = to_ms_since_boot(get_absolute_time());
286
287 if (req.getHeader("Connection") == "close")
288 {
289 TRACE("[HttpServer] Client requested Connection: close, closing connection\n");
290 return;
291 }
292
293 if (to_ms_since_boot(get_absolute_time()) - lastActivity > idleTimeoutMs)
294 {
295 printf("[HttpServer] Idle timeout reached, closing connection\n");
296 return;
297 }
298
299 conn->close();
300 int64_t end = to_ms_since_boot(get_absolute_time());
301 TRACE("[HttpServer] Client handled in %lld ms\n", end - start);
302}
#define TRACE(...)
Default trace (INFO level).
Definition DebugTrace.h:187
Forward declaration for potential routing needs.
Definition HttpRequest.h:32
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.
static HttpRequest receive(Tcp *tcp)
Receive and parse an HTTP request from a socket.
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.
bool start()
Start the HTTP server as a FreeRTOS task.
bool handleRequest(HttpRequest &req, HttpResponse &res)
Handle an incoming HTTP request.
Definition Router.cpp:228
int close()
Close the connection and free resources.
Definition Tcp.cpp:443
#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)

References Tcp::close(), HttpRequest::getBody(), HttpRequest::getBoundary(), HttpRequest::getContentLength(), HttpRequest::getContentType(), HttpRequest::getCookies(), HttpRequest::getFormParams(), HttpRequest::getHeader(), HttpRequest::getHeaderEnd(), HttpRequest::getHeaders(), HttpRequest::getMethod(), HttpRequest::getPath(), HttpRequest::getQuery(), HttpRequest::getQueryParams(), HttpRequest::getUri(), Router::handleRequest(), HTTP_IDLE_TIMEOUT, HttpRequest::isMultipart(), QUIET_PRINTF, HttpRequest::receive(), router, JsonResponse::sendError(), HttpResponse::setHeader(), start(), and TRACE.

Referenced by startHandlingClient().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ handleClientTask()

static void HttpServer::handleClientTask ( void *  pvParameters)
static
Parameters
pvParametersPointer to TaskParams (including Tcp*)

Referenced by startHandlingClient().

+ Here is the caller graph for this function:

◆ initListener()

Tcp * HttpServer::initListener ( )
Returns
Tcp* TCP connection instance

Definition at line 176 of file HttpServer.cpp.

177{
179 return nullptr;
180 }
181 // Once server is listening
183 AppContext::get<EventManager>()->postEvent(e); // tell others that we are up
184 return &listener;
185}
static constexpr std::uintptr_t getTypeKey()
Definition AppContext.h:91
bool bindAndListen(int port)
Bind and listen on a port for incoming connections (for server use).
Definition Tcp.cpp:542
Represents a framework event, optionally carrying payload data.
Definition Event.h:24

References Tcp::bindAndListen(), AppContext::getTypeKey(), HttpServerStarted, listener, and port.

Referenced by run().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ initNetwork()

bool HttpServer::initNetwork ( )

Initialize the network stack (wait for DHCP or static IP).

Returns
true if successful.
Returns
true if successful.

Definition at line 154 of file HttpServer.cpp.

155{
156 struct netif *netif;
157
158 //TRACE("Waiting for DHCP lease...\n");
159
160 while (true)
161 {
162 netif = netif_list;
163 if (netif && netif->ip_addr.addr != 0)
164 {
165 break;
166 }
167 vTaskDelay(pdMS_TO_TICKS(10));
168 }
169
170 //TRACE("Assigned IP Address: %s\n", ip4addr_ntoa(&netif->ip_addr));
171 return true;
172}

Referenced by run().

+ Here is the caller graph for this function:

◆ receiveRequest()

HttpRequest HttpServer::receiveRequest ( Tcp conn,
char *  method,
char *  path,
std::string &  body,
size_t &  contentLength,
std::unordered_map< std::string, std::string > &  headers 
)
Parameters
Tcp*TCP connection instance
methodOutput buffer for method.
pathOutput buffer for path.
bodyOutput body content.
contentLengthOutput content length.
headersOutput map of parsed headers.
Returns
Parsed HttpRequest object.

◆ run()

void HttpServer::run ( )

Main server loop: initializes, binds, and begins accepting connections.

Definition at line 103 of file HttpServer.cpp.

104{
105
106 printf("[HttpServer] Starting HTTP Server on port %d\n", port);
107
108 if (!initNetwork())
109 {
110 return;
111 }
112
114 if (!listener)
115 {
116 printf("[HttpServer] Failed to initialize listener\n");
117 return;
118 }
119
121
122 // Optional: store listener as a class member if needed later
123 while (true)
124 {
125 TRACE("[HttpServer] Waiting for client connection...\n");
126 Tcp* conn = listener->accept();
127 if (conn)
128 {
129 QUIET_PRINTF("\n===== HTTP CLIENT ACCEPTED ====\n");
130 QUIET_PRINTF("[HttpServer] Accepted client connection\n");
132 vTaskDelay(pdMS_TO_TICKS(10));
133
134 QUIET_PRINTF("[HttpServer] Client connection handled\n");
135 QUIET_PRINTF("===============================\n\n");
136 #if !defined(HTTP_SERVER_USE_TASK_PER_CLIENT)
137 delete conn;
138 #endif
139 }
140 else
141 {
142 warning("[HttpServer] Failed to accept client connection\n");
143 vTaskDelay(pdMS_TO_TICKS(10)); // Wait before retrying
144 }
145
146 }
147
148 // Note: we never reach here in this model
149 delete listener;
150}
bool initNetwork()
Initialize the network stack (wait for DHCP or static IP).
Tcp * initListener()
Create, bind, and listen on the server.
void startHandlingClient(Tcp *conn)
Spawn a task to handle the client connection.
General-purpose TCP socket wrapper with optional TLS support via mbedTLS (altcp).
Definition Tcp.h:39
Tcp * accept()
Accept a new incoming connection (for server use).
Definition Tcp.cpp:491
void warning(const std::string &msg)
Definition utility.cpp:215

References Tcp::accept(), AppContext::getTypeKey(), HttpServerStarted, initListener(), initNetwork(), listener, port, QUIET_PRINTF, startHandlingClient(), TRACE, and warning().

Referenced by startServerTask().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ start()

bool HttpServer::start ( )

Start the HTTP server as a FreeRTOS task.

Returns
true if task created successfully.
Returns
true if task created successfully.

Definition at line 84 of file HttpServer.cpp.

85{
87 return xTaskCreateStatic(startServerTask, "HttpServer", HTTP_STACK_SIZE, this, 5, xStack, &xTaskBuffer);
88}
SemaphoreHandle_t clientSemaphore
static constexpr int MAX_CONCURRENT_CLIENTS
#define HTTP_STACK_SIZE
Definition HttpServer.h:23
static void startServerTask(void *pvParameters)
Launch the HTTP server task (used by FreeRTOS).
static StackType_t xStack[HTTP_STACK_SIZE]
Stack for static FreeRTOS task.
Definition HttpServer.h:117
static StaticTask_t xTaskBuffer
Task control block buffer.
Definition HttpServer.h:118

References clientSemaphore, HTTP_STACK_SIZE, MAX_CONCURRENT_CLIENTS, startServerTask(), xStack, and xTaskBuffer.

Referenced by handleClient(), and App::onEvent().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ startHandlingClient()

void HttpServer::startHandlingClient ( Tcp conn)
Parameters
Tcp*TCP connection instance.

Definition at line 187 of file HttpServer.cpp.

188{
189#ifdef HTTP_SERVER_USE_TASK_PER_CLIENT
190 if (xSemaphoreTake(clientSemaphore, pdMS_TO_TICKS(100)) == pdPASS)
191 {
192 TaskParams *params = new TaskParams{this, conn};
193
194 if (xTaskCreate(handleClientTask, "HttpClient", 4096, params, 4, NULL) == pdPASS)
195 {
196 TRACE("Client task created successfully");
197 }
198 else
199 {
200 TRACE("Failed to create client task");
201 conn->close();
202 delete params;
203 xSemaphoreGive(clientSemaphore);
204 }
205 }
206 else
207 {
208 TRACE("Max concurrent clients reached, closing connection");
209 conn->close();
210 // Optional: return a "503 Service Unavailable" if desired
211 }
212#else
213 handleClient(conn);
214
215#endif
216}
void handleClient(Tcp *conn)
Accept a client connection and handle it directly (not task-based).
static void handleClientTask(void *pvParameters)
Handle client logic inside a FreeRTOS task.
Parameters passed to the per-client handler task.

References clientSemaphore, Tcp::close(), handleClient(), handleClientTask(), and TRACE.

Referenced by run().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ startServerTask()

void HttpServer::startServerTask ( void *  pvParameters)
static

Launch the HTTP server task (used by FreeRTOS).

Parameters
pvParametersPointer to HttpServer instance.
Parameters
pvParametersPointer to HttpServer instance.

Definition at line 91 of file HttpServer.cpp.

92{
93 HttpServer *server = static_cast<HttpServer *>(pvParameters);
94 server->run();
95 vTaskDelete(NULL);
96}
HTTP Server that listens for incoming connections and dispatches requests.
Definition HttpServer.h:29
void run()
Main server loop: initializes, binds, and begins accepting connections.

References run().

Referenced by start().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Member Data Documentation

◆ BOUNDARY_MAX_LEN

constexpr int HttpServer::BOUNDARY_MAX_LEN = 128
staticconstexprprivate

Definition at line 115 of file HttpServer.h.

◆ BUFFER_SIZE

constexpr int HttpServer::BUFFER_SIZE = 1460
staticconstexprprivate

Definition at line 114 of file HttpServer.h.

◆ listener

Tcp HttpServer::listener
private

Definition at line 113 of file HttpServer.h.

Referenced by initListener(), and run().

◆ port

int HttpServer::port
private

Port number to listen on.

Definition at line 110 of file HttpServer.h.

Referenced by initListener(), and run().

◆ router

Router& HttpServer::router
private

Definition at line 111 of file HttpServer.h.

Referenced by getRouter(), and handleClient().

◆ xStack

StackType_t HttpServer::xStack
staticprivate

Definition at line 117 of file HttpServer.h.

Referenced by start().

◆ xTaskBuffer

StaticTask_t HttpServer::xTaskBuffer
staticprivate

Definition at line 118 of file HttpServer.h.

Referenced by start().


The documentation for this class was generated from the following files: