51 const std::string bearerPrefix =
"Bearer ";
52 if (auth_header.compare(0, bearerPrefix.size(), bearerPrefix) == 0)
54 return auth_header.substr(bearerPrefix.size());
63 lock_ = xSemaphoreCreateRecursiveMutex();
71 std::string auth_header = req.
getHeader(
"Authorization");
75 TRACE(
"Error: Missing or invalid Authorization header format\n");
87#ifdef PICO_HTTP_ENABLE_JWT
90 TRACE(
"Handling /auth\n");
91 std::string auth_header = req.
getHeader(
"Authorization");
92 if (auth_header.empty())
94 TRACE(
"Missing Authorization header\n");
101 TRACE(
"Token: %s\n", token.c_str());
117#ifdef PICO_HTTP_ENABLE_JWT
123 TRACE(
"Authorization required for route: %s\n", route.
path.c_str());
125 TRACE(
"Token: %s\n", token.c_str());
130 TRACE(
"Authorization failed\n");
136 TRACE(
"No authorization required for route: %s\n", route.
path.c_str());
145 const std::string &path,
147 std::vector<Middleware> middleware)
149 TRACE(
"Adding route: %s %s\n", method.c_str(), path.c_str());
151 std::string regex_pattern =
"^" + path;
152 bool is_dynamic =
false;
153 std::vector<std::string> paramNames;
156 while ((pos = regex_pattern.find(
"{", pos)) != std::string::npos)
158 size_t end = regex_pattern.find(
"}", pos);
159 if (end != std::string::npos)
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,
"([^/]+)");
165 pos += std::string(
"([^/]+)").size();
173 if (regex_pattern ==
"/.*")
175 regex_pattern =
"^/(.*)$";
178 regex_pattern +=
"$";
184 if (!mw(req, res, match))
188 for (
const auto &mw : middleware)
190 if (!mw(req, res, match))
194 handler(req, res, match);
199 r[method].emplace_back(method, regex_pattern, finalHandler, is_dynamic, !middleware.empty(), paramNames);
205 TRACE(
"Adding catch-all GET route\n");
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);
231 bool matched =
false;
232 const Route *matchedRoute =
nullptr;
233 std::vector<std::string> params;
241 for (
const auto &route : it->second)
243 TRACE(
"Checking route: %s\n", route.
path.c_str());
246 const std::string &path = req.
getPath();
249 for (
size_t i = 1; i < match.size(); ++i)
251 TRACE(
"Matched param %zu: %s\n", i, match[i].str().c_str());
252 params.push_back(
urlDecode(match[i].str()));
254 matchedRoute = &route;
256 TRACE(
"Matched route: %s\n", route.
path.c_str());
261 TRACE(
"Matched: %s\n", matched ?
"true" :
"false");
262 if (matched && matchedRoute)
268 for (
size_t i = 0; i < names.size() && i < params.size(); ++i)
270 match.
named[names[i]] = params[i];
273 TRACE(
"Matched route: %s\n", matchedRoute->
path.c_str());
274 matchedRoute->
handler(req, res, match);
278 TRACE(
"No matching regular route found\n");
282 TRACE(
"Falling back to catch-all GET route\n");
299 for (
const auto &method_pair :
routes)
301 TRACE(
"Method: %s\n", method_pair.first.c_str());
302 for (
const auto &route : method_pair.second)
304 TRACE(
" Route: %s, Dynamic: %s, Requires Auth: %s\n",
328void Router::withRoutes(
const std::function<
void(std::unordered_map<std::string, std::vector<Route>> &)> &fn)
330 const char* taskName = pcTaskGetName(
nullptr);
332 if (xSemaphoreTakeRecursive(
lock_, pdMS_TO_TICKS(5000)) != pdTRUE)
334 printf(
"[Router] [%s] ERROR - failed to acquire lock within timeout\n", taskName);
340 xSemaphoreGiveRecursive(
lock_);
341 vTaskDelay(pdMS_TO_TICKS(1));
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).
Defines the HttpRequest class for handling HTTP requests: headers, method, path, query string,...
HTTP HttpResponse class for managing status, headers, body, and streaming support.
Utility functions to send standard JSON responses using nlohmann::json.
Stateless singleton class for creating and validating JWTs using HMAC-SHA256.
Middleware definitions for HTTP routing (e.g., logging, auth). Part of the PicoFramework HTTP server....
static std::string extractBearerToken(const std::string &auth_header)
HTTP routing with middleware and optional JWT-based authorization. Part of the PicoFramework HTTP ser...
std::function< void(HttpRequest &, HttpResponse &, const RouteMatch &)> RouteHandler
Function signature for HTTP route handlers.
std::function< bool(HttpRequest &, HttpResponse &, const RouteMatch &)> Middleware
Function signature for middleware.
static constexpr std::uintptr_t getTypeKey()
void handle_list_directory(HttpRequest &req, HttpResponse &res, const RouteMatch &match)
Handle requests to list directory contents.
void handle_static_request(HttpRequest &req, HttpResponse &res, const RouteMatch &match)
Handle requests for static file content.
Forward declaration for potential routing needs.
const std::string & getMethod() const
Get the HTTP method.
const std::string & getPath() const
Get the parsed request path (without query string).
std::string getHeader(const std::string &field) const
Get a specific header field (case-insensitive).
Represents an HTTP response object.
The central router for handling HTTP requests and middleware.
std::unordered_map< std::string, std::vector< Route > > routes
void withRoutes(const std::function< void(std::unordered_map< std::string, std::vector< Route > > &)> &fn)
bool isAuthorizedForRoute(const Route &route, HttpRequest &req, HttpResponse &res)
Check if a route requires and is granted JWT authorization.
void addCatchAllGetRoute(RouteHandler handler, std::vector< Middleware > middleware={})
Register a catch-all route with optional middleware.
static StaticSemaphore_t lockBuffer_
HttpFileserver fileServer
Internal file server instance.
void serveStatic(HttpRequest &req, HttpResponse &res, const RouteMatch &match)
Serve static files from the internal HttpFileserver.
Route catchallGetRoute
Catch-all route for unmatched requests.
Router()
Construct the router instance.
void printRoutes()
Print all registered routes to stdout.
std::string getAuthorizationToken(const HttpRequest &req)
Returns the cached Authorization token, or extracts it from the request.
bool handleRequest(HttpRequest &req, HttpResponse &res)
Handle an incoming HTTP request.
bool hasCatchallGetRoute
Flag to indicate if a catch-all route exists.
void listDirectory(HttpRequest &req, HttpResponse &res, const RouteMatch &match)
Convenience method to list directory from the internal HttpFileserver.
std::vector< Middleware > globalMiddleware
void addRoute(const std::string &method, const std::string &path, RouteHandler handler, std::vector< Middleware > middleware={})
Register a route with optional middleware.
void use(Middleware middleware)
Register a global middleware function.
Delegates to user or system configuration.
void sendError(HttpResponse &res, int statusCode, const std::string &code, const std::string &message)
void sendSuccess(HttpResponse &res, const nlohmann::json &data, const std::string &message)
Represents a match of a route against an incoming HTTP request.
std::vector< std::string > ordered
std::unordered_map< std::string, std::string > named
Represents a single HTTP route.
std::vector< std::string > paramNames
std::string urlDecode(const std::string &src)
Utility functions for URL decoding, form parsing, MIME type lookup, and IP address extraction.
System utilities for diagnostics, memory, stack usage, and tracing.