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

The central router for handling HTTP requests and middleware. More...

#include <Router.h>

+ Collaboration diagram for Router:

Public Member Functions

 Router ()
 Construct the router instance.
 
 Router (const Router &)=delete
 
Routeroperator= (const Router &)=delete
 
void use (Middleware middleware)
 Register a global middleware function.
 
void addRoute (const std::string &method, const std::string &path, RouteHandler handler, std::vector< Middleware > middleware={})
 Register a route with optional middleware.
 
void addCatchAllGetRoute (RouteHandler handler, std::vector< Middleware > middleware={})
 Register a catch-all route with optional middleware.
 
void addRoute (Router &router, const std::string &method, const std::string &path, std::function< void(HttpRequest &, HttpResponse &)> simpleHandler)
 
bool handleRequest (HttpRequest &req, HttpResponse &res)
 Handle an incoming HTTP request.
 
bool extractAuthorizationToken (const std::string &auth_header)
 Built-in route handler for /auth token testing.
 
std::string getAuthorizationToken (const HttpRequest &req)
 Returns the cached Authorization token, or extracts it from the request.
 
bool isAuthorizedForRoute (const Route &route, HttpRequest &req, HttpResponse &res)
 Check if a route requires and is granted JWT authorization.
 
void printRoutes ()
 Print all registered routes to stdout.
 
HttpFileservergetFileHandler ()
 Get the file server instance.
 
void serveStatic (HttpRequest &req, HttpResponse &res, const RouteMatch &match)
 Serve static files from the internal HttpFileserver.
 
void listDirectory (HttpRequest &req, HttpResponse &res, const RouteMatch &match)
 Convenience method to list directory from the internal HttpFileserver.
 

Private Member Functions

void withRoutes (const std::function< void(std::unordered_map< std::string, std::vector< Route > > &)> &fn)
 

Private Attributes

HttpFileserver fileServer
 Internal file server instance.
 
std::unordered_map< std::string, std::vector< Route > > routes
 
Route catchallGetRoute
 Catch-all route for unmatched requests.
 
bool hasCatchallGetRoute = false
 Flag to indicate if a catch-all route exists.
 
std::string cached_token
 Cached Bearer token.
 
std::vector< MiddlewareglobalMiddleware
 
SemaphoreHandle_t lock_ = xSemaphoreCreateRecursiveMutexStatic(&lockBuffer_)
 

Static Private Attributes

static StaticSemaphore_t lockBuffer_
 

Detailed Description

Supports:

  • Dynamic route registration
  • Regex-based matching
  • Global and per-route middleware
  • Optional JWT authentication

Definition at line 59 of file Router.h.

Constructor & Destructor Documentation

◆ Router() [1/2]

Router::Router ( )

Construct the router instance.

Definition at line 61 of file Router.cpp.

62{
63 lock_ = xSemaphoreCreateRecursiveMutex();
65}
#define configASSERT(x)
SemaphoreHandle_t lock_
Definition Router.h:183

References configASSERT, and lock_.

◆ Router() [2/2]

Router::Router ( const Router )
delete

Member Function Documentation

◆ addCatchAllGetRoute()

void Router::addCatchAllGetRoute ( RouteHandler  handler,
std::vector< Middleware middleware = {} 
)
Parameters
methodHTTP method
pathURL path (can include {params})
handlerHandler to invoke on match
middlewareOptional list of middleware specific to this route

Definition at line 203 of file Router.cpp.

204{
205 TRACE("Adding catch-all GET route\n");
206
207 RouteHandler finalHandler = [handler, this, middleware](HttpRequest &req, HttpResponse &res, const RouteMatch &match) {
208 for (const auto &mw : globalMiddleware)
209 if (!mw(req, res, match)) return;
210 for (const auto &mw : middleware)
211 if (!mw(req, res, match)) return;
212 handler(req, res, match);
213 };
214
215 withRoutes([&](auto &) {
217 "GET",
218 "/(.*)",
219 finalHandler,
220 true, // authRequired
221 !middleware.empty(), // hasMiddleware
222 {} // vector<string>
223 );
224 hasCatchallGetRoute = true;
225 });
226}
#define TRACE(...)
Default trace (INFO level).
Definition DebugTrace.h:187
std::function< void(HttpRequest &, HttpResponse &, const RouteMatch &)> RouteHandler
Function signature for HTTP route handlers.
Definition Router.h:41
Forward declaration for potential routing needs.
Definition HttpRequest.h:32
Represents an HTTP response object.
void withRoutes(const std::function< void(std::unordered_map< std::string, std::vector< Route > > &)> &fn)
Definition Router.cpp:328
Route catchallGetRoute
Catch-all route for unmatched requests.
Definition Router.h:177
bool hasCatchallGetRoute
Flag to indicate if a catch-all route exists.
Definition Router.h:178
std::vector< Middleware > globalMiddleware
Definition Router.h:180
Represents a match of a route against an incoming HTTP request.
Definition RouteTypes.h:18
Represents a single HTTP route.
Definition RouteTypes.h:42

References catchallGetRoute, globalMiddleware, hasCatchallGetRoute, TRACE, and withRoutes().

Referenced by DashboardController::initRoutes().

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

◆ addRoute() [1/2]

void Router::addRoute ( const std::string &  method,
const std::string &  path,
RouteHandler  handler,
std::vector< Middleware middleware = {} 
)

Check if a route requires and is granted JWT authorization.

Parameters
methodHTTP method
pathURL path (can include {params})
handlerHandler to invoke on match
middlewareOptional list of middleware specific to this route
routeThe matched route
reqHTTP request
resHTTP response
Returns
true if access is granted

Register a route with optional middleware.

Check if a route requires and is granted JWT authorization.

Parameters
methodHTTP method
pathURL path (can include {params})
handlerHandler to invoke on match
middlewareOptional list of middleware specific to this route
routeThe matched route
reqHTTP request
resHTTP response
Returns
true if access is granted

Definition at line 144 of file Router.cpp.

148{
149 TRACE("Adding route: %s %s\n", method.c_str(), path.c_str());
150
151 std::string regex_pattern = "^" + path;
152 bool is_dynamic = false;
153 std::vector<std::string> paramNames;
154 size_t pos = 0;
155
156 while ((pos = regex_pattern.find("{", pos)) != std::string::npos)
157 {
158 size_t end = regex_pattern.find("}", pos);
159 if (end != std::string::npos)
160 {
161 std::string paramName = regex_pattern.substr(pos + 1, end - pos - 1);
162 paramNames.push_back(paramName);
163 regex_pattern.replace(pos, end - pos + 1, "([^/]+)");
164 is_dynamic = true;
165 pos += std::string("([^/]+)").size();
166 }
167 else
168 {
169 break;
170 }
171 }
172
173 if (regex_pattern == "/.*")
174 {
175 regex_pattern = "^/(.*)$";
176 is_dynamic = true;
177 }
178 regex_pattern += "$";
179
180 RouteHandler finalHandler = [handler, paramNames, this, middleware](HttpRequest &req, HttpResponse &res, const RouteMatch &match)
181 {
182 for (const auto &mw : this->globalMiddleware)
183 {
184 if (!mw(req, res, match))
185 return;
186 }
187
188 for (const auto &mw : middleware)
189 {
190 if (!mw(req, res, match))
191 return;
192 }
193
194 handler(req, res, match);
195 };
196
197 withRoutes([&](auto &r)
198 {
199 r[method].emplace_back(method, regex_pattern, finalHandler, is_dynamic, !middleware.empty(), paramNames);
200 });
201}

References globalMiddleware, TRACE, and withRoutes().

Referenced by addRoute(), App::initRoutes(), DashboardController::initRoutes(), and GpioController::initRoutes().

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

◆ addRoute() [2/2]

void Router::addRoute ( Router router,
const std::string &  method,
const std::string &  path,
std::function< void(HttpRequest &, HttpResponse &)>  simpleHandler 
)
inline

Definition at line 97 of file Router.h.

100 {
101 router.addRoute(method, path,
102 [=](HttpRequest& req, HttpResponse& res, const RouteMatch&) {
103 simpleHandler(req, res);
104 });
105 }
void addRoute(const std::string &method, const std::string &path, RouteHandler handler, std::vector< Middleware > middleware={})
Register a route with optional middleware.
Definition Router.cpp:144

References addRoute().

+ Here is the call graph for this function:

◆ extractAuthorizationToken()

bool Router::extractAuthorizationToken ( const std::string &  auth_header)
Parameters
reqIncoming request
resHttpResponse to send
paramsUnused in this handler
Returns
true on success

Extracts and caches a Bearer token from an Authorization header.

Parameters
auth_headerRaw header string
Returns
true if token is valid

◆ getAuthorizationToken()

std::string Router::getAuthorizationToken ( const HttpRequest req)

Returns the cached Authorization token, or extracts it from the request.

Parameters
reqThe incoming request
Returns
Extracted Bearer token or empty string
Parameters
reqThe incoming request
Returns
Extracted Bearer token or empty string

Definition at line 69 of file Router.cpp.

70{
71 std::string auth_header = req.getHeader("Authorization");
72 std::string token = extractBearerToken(auth_header);
73 if (token.empty())
74 {
75 TRACE("Error: Missing or invalid Authorization header format\n");
76 }
77 return token;
78}
static std::string extractBearerToken(const std::string &auth_header)
Definition Router.cpp:49
std::string getHeader(const std::string &field) const
Get a specific header field (case-insensitive).

References extractBearerToken(), HttpRequest::getHeader(), and TRACE.

+ Here is the call graph for this function:

◆ getFileHandler()

HttpFileserver & Router::getFileHandler ( )
inline
Returns
A reference to the internal HttpFileserver

Definition at line 162 of file Router.h.

162{ return fileServer; }
HttpFileserver fileServer
Internal file server instance.
Definition Router.h:175

References fileServer.

◆ handleRequest()

bool Router::handleRequest ( HttpRequest req,
HttpResponse res 
)
Parameters
reqFully parsed HttpRequest object
resHttpResponse to send
Returns
true if the request was handled
false if no matching route was found

Definition at line 228 of file Router.cpp.

229{
230 TRACE("Router::handleRequest: %s %s\n", req.getMethod().c_str(), req.getPath().c_str());
231 bool matched = false;
232 const Route *matchedRoute = nullptr;
233 std::vector<std::string> params;
234
235 withRoutes([&](auto &r)
236 {
237 auto it = r.find(req.getMethod());
238 if (it == r.end())
239 return;
240
241 for (const auto &route : it->second)
242 {
243 TRACE("Checking route: %s\n", route.path.c_str());
244
245 std::smatch match;
246 const std::string &path = req.getPath();
247 if (std::regex_match(path, match, route.compiledRegex)) // <--- USE precompiled
248 {
249 for (size_t i = 1; i < match.size(); ++i)
250 {
251 TRACE("Matched param %zu: %s\n", i, match[i].str().c_str());
252 params.push_back(urlDecode(match[i].str()));
253 }
254 matchedRoute = &route;
255 matched = true;
256 TRACE("Matched route: %s\n", route.path.c_str());
257 return;
258 }
259 }
260 });
261 TRACE("Matched: %s\n", matched ? "true" : "false");
262 if (matched && matchedRoute)
263 {
264 RouteMatch match;
265 match.ordered = params;
266 const auto &names = matchedRoute->paramNames;
267
268 for (size_t i = 0; i < names.size() && i < params.size(); ++i)
269 {
270 match.named[names[i]] = params[i];
271 }
272
273 TRACE("Matched route: %s\n", matchedRoute->path.c_str());
274 matchedRoute->handler(req, res, match);
275 return true;
276 }
277
278 TRACE("No matching regular route found\n");
279
280 if (req.getMethod() == "GET" && hasCatchallGetRoute)
281 {
282 TRACE("Falling back to catch-all GET route\n");
283 RouteMatch dummyMatch; // Dummy match for catch-all route
284 catchallGetRoute.handler(req, res, dummyMatch);
285 return true;
286 }
287
288 printRoutes();
289 return false;
290}
const std::string & getMethod() const
Get the HTTP method.
const std::string & getPath() const
Get the parsed request path (without query string).
void printRoutes()
Print all registered routes to stdout.
Definition Router.cpp:294
std::vector< std::string > ordered
Definition RouteTypes.h:19
std::unordered_map< std::string, std::string > named
Definition RouteTypes.h:20
std::vector< std::string > paramNames
Definition RouteTypes.h:49
RouteHandler handler
Definition RouteTypes.h:46
std::string path
Definition RouteTypes.h:44
std::string urlDecode(const std::string &src)
Definition url_utils.cpp:28

References catchallGetRoute, Route::compiledRegex, HttpRequest::getMethod(), HttpRequest::getPath(), Route::handler, hasCatchallGetRoute, RouteMatch::named, RouteMatch::ordered, Route::paramNames, Route::path, printRoutes(), TRACE, urlDecode(), and withRoutes().

Referenced by HttpServer::handleClient().

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

◆ isAuthorizedForRoute()

bool Router::isAuthorizedForRoute ( const Route route,
HttpRequest req,
HttpResponse res 
)
inline
Parameters
routeThe matched route
reqHTTP request
resHTTP response
Returns
true if access is granted

Definition at line 151 of file Router.h.

151{ return true; }

◆ listDirectory()

void Router::listDirectory ( HttpRequest req,
HttpResponse res,
const RouteMatch match 
)

Convenience method to list directory from the internal HttpFileserver.

Definition at line 321 of file Router.cpp.

322{
323
324 fileServer.handle_list_directory(req, res, match);
325 ;
326}
void handle_list_directory(HttpRequest &req, HttpResponse &res, const RouteMatch &match)
Handle requests to list directory contents.

References fileServer, and HttpFileserver::handle_list_directory().

Referenced by DashboardController::initRoutes().

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

◆ operator=()

Router & Router::operator= ( const Router )
delete

◆ printRoutes()

void Router::printRoutes ( )

Definition at line 294 of file Router.cpp.

295{
296 TRACE("Routes:\n");
297 withRoutes([&](auto &r)
298 {
299 for (const auto &method_pair : routes)
300 {
301 TRACE("Method: %s\n", method_pair.first.c_str());
302 for (const auto &route : method_pair.second)
303 {
304 TRACE(" Route: %s, Dynamic: %s, Requires Auth: %s\n",
305 route.path.c_str(),
306 route.isDynamic ? "true" : "false",
307 route.requiresAuth ? "true" : "false");
308 }
309 } });
310}
std::unordered_map< std::string, std::vector< Route > > routes
Definition Router.h:176

References Route::isDynamic, Route::path, Route::requiresAuth, routes, TRACE, and withRoutes().

Referenced by handleRequest().

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

◆ serveStatic()

void Router::serveStatic ( HttpRequest req,
HttpResponse res,
const RouteMatch match 
)

Serve static files from the internal HttpFileserver.

Definition at line 314 of file Router.cpp.

315{
316 fileServer.handle_static_request(req, res, match);
317}
void handle_static_request(HttpRequest &req, HttpResponse &res, const RouteMatch &match)
Handle requests for static file content.

References fileServer, and HttpFileserver::handle_static_request().

Referenced by DashboardController::initRoutes().

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

◆ use()

void Router::use ( Middleware  middleware)
Parameters
middlewareMiddleware to apply to all routes.

Register a global middleware function.

Parameters
middlewareMiddleware to apply to all routes.

Definition at line 110 of file Router.cpp.

111{
112 globalMiddleware.push_back(middleware);
113}

References globalMiddleware.

◆ withRoutes()

void Router::withRoutes ( const std::function< void(std::unordered_map< std::string, std::vector< Route > > &)> &  fn)
private

Definition at line 328 of file Router.cpp.

329{
330 const char* taskName = pcTaskGetName(nullptr);
331
332 if (xSemaphoreTakeRecursive(lock_, pdMS_TO_TICKS(5000)) != pdTRUE)
333 {
334 printf("[Router] [%s] ERROR - failed to acquire lock within timeout\n", taskName);
335 return;
336 }
337
338 fn(routes);
339
340 xSemaphoreGiveRecursive(lock_);
341 vTaskDelay(pdMS_TO_TICKS(1)); // Give any pending route-registration task a chance to run
342}

References lock_, and routes.

Referenced by addCatchAllGetRoute(), addRoute(), handleRequest(), and printRoutes().

+ Here is the caller graph for this function:

Member Data Documentation

◆ cached_token

std::string Router::cached_token
private

Definition at line 179 of file Router.h.

◆ catchallGetRoute

Route Router::catchallGetRoute
private

Definition at line 177 of file Router.h.

Referenced by addCatchAllGetRoute(), and handleRequest().

◆ fileServer

HttpFileserver Router::fileServer
private

Definition at line 175 of file Router.h.

Referenced by getFileHandler(), listDirectory(), and serveStatic().

◆ globalMiddleware

std::vector<Middleware> Router::globalMiddleware
private

Definition at line 180 of file Router.h.

Referenced by addCatchAllGetRoute(), addRoute(), and use().

◆ hasCatchallGetRoute

bool Router::hasCatchallGetRoute = false
private

Definition at line 178 of file Router.h.

Referenced by addCatchAllGetRoute(), and handleRequest().

◆ lock_

SemaphoreHandle_t Router::lock_ = xSemaphoreCreateRecursiveMutexStatic(&lockBuffer_)
private

Definition at line 183 of file Router.h.

Referenced by Router(), and withRoutes().

◆ lockBuffer_

StaticSemaphore_t Router::lockBuffer_
staticprivate

Definition at line 182 of file Router.h.

◆ routes

std::unordered_map<std::string, std::vector<Route> > Router::routes
private

Definition at line 176 of file Router.h.

Referenced by printRoutes(), and withRoutes().


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