27#include <lwip/sockets.h>
28#include <unordered_map>
58 TRACE(
"Storage mounted successfully\n");
63 printf(
"Storage mount failed\n");
72 return storage->listDirectory(path, out);
78 std::string path = uri;
83 printf(
"Storage mount failed\n");
92 TRACE(
"Storage is not mounted — static file access failed\n");
98 printf(
"File not found: %s\n", path.c_str());
112 TRACE(
"Serving file: %s, size: %zu bytes, MIME type: %s\n", path.c_str(), fileSize, mimeType.c_str());
114 if (mimeType ==
"text/html" || mimeType ==
"application/javascript" || mimeType ==
"text/css")
117 const uint8_t gzip_magic_number[] = {0x1F, 0x8B};
118 std::string magic_number;
121 TRACE(
"Read magic number in hex: ");
122 for (
size_t i = 0; i < magic_number.size(); ++i)
124 TRACE(
"%02X ",
static_cast<unsigned char>(magic_number[i]));
127 if (magic_number[0] == gzip_magic_number[0] && magic_number[1] == gzip_magic_number[1])
129 TRACE(
"File is already gzipped: %s\n", path.c_str());
130 TRACE(
"Setting Content-Encoding to gzip\n");
131 res.
set(
"Content-Encoding",
"gzip");
136 res.
start(200, fileSize, mimeType.c_str());
140 res.
writeChunk(
reinterpret_cast<const char*
>(data), len);
160 std::string directory_path = req.
getPath();
161 int pos = directory_path.find(
"/api/v1/ls");
162 if (pos != std::string::npos)
164 directory_path = directory_path.substr(pos + strlen(
"/api/v1/ls"));
167 if (directory_path.empty())
169 directory_path =
"/";
172 std::vector<FileInfo> entries;
175 res.
sendError(404,
"not_found",
"Directory not found or inaccessible");
179 nlohmann::json fileArray = nlohmann::json::array();
180 for (
const auto &entry : entries)
182 fileArray.push_back({{
"name", entry.name},
183 {
"size", entry.size},
184 {
"type", entry.isDirectory ?
"directory" :
"file"}});
187 nlohmann::json result = {
188 {
"path", directory_path},
189 {
"files", fileArray}};
191 res.
sendSuccess(result,
"Directory listed successfully.");
195bool ends_with(
const std::string &str,
const std::string &suffix)
197 if (str.length() < suffix.length())
199 return std::equal(suffix.rbegin(), suffix.rend(), str.rbegin());
206 const std::string &uri = req.
getPath();
207 printf(
"Serving static request for URI: %s\n", uri.c_str());
210 printf(
"Decoded URI: %s\n", filePath.c_str());
212 if (uri.empty() || uri ==
"/")
214 filePath =
"/index.html";
224 TRACE(
"Getting MIME type for file: %s\n", filePath.c_str());
226 static const std::unordered_map<std::string, std::string> mimeTypes = {
227 {
".html",
"text/html"},
228 {
".css",
"text/css"},
229 {
".js",
"application/javascript"},
230 {
".json",
"application/json"},
231 {
".jpg",
"image/jpeg"},
232 {
".jpeg",
"image/jpeg"},
233 {
".png",
"image/png"},
234 {
".gif",
"image/gif"},
235 {
".txt",
"text/plain"},
236 {
".xml",
"application/xml"},
237 {
".pdf",
"application/pdf"},
238 {
".zip",
"application/zip"},
239 {
".gz",
"application/x-gzip-compressed"},
240 {
".tar",
"application/x-tar"},
241 {
".mp4",
"video/mp4"},
242 {
".webm",
"video/webm"},
243 {
".ogg",
"audio/ogg"},
244 {
".flac",
"audio/flac"},
245 {
".aac",
"audio/aac"},
246 {
".mp4",
"video/mp4"},
247 {
".mp3",
"audio/mpeg"},
248 {
".wav",
"audio/wav"},
249 {
".csv",
"text/csv"}};
251 size_t extPos = filePath.find_last_of(
".");
252 if (extPos != std::string::npos)
254 std::string ext = filePath.substr(extPos);
255 TRACE(
"Extracted extension: %s\n", ext.c_str());
257 auto it = mimeTypes.find(ext);
258 if (it != mimeTypes.end())
264 return "application/octet-stream";
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).
bool ends_with(const std::string &str, const std::string &suffix)
HTTP file server and file handling helpers for static content.
Utility functions to send standard JSON responses using nlohmann::json.
Abstract interface for file and directory storage backends.
static constexpr std::uintptr_t getTypeKey()
FileHandler()
Construct a new FileHandler object.
bool serveFile(HttpResponse &res, const char *uri)
Serve a file to the client via the HttpResponse object.
StorageManager * storageManager
bool listDirectory(const std::string &path, std::vector< FileInfo > &out)
Return a list of a given directory.
bool init()
Initialize and mount the storage (e.g., SD card).
HTTP-level controller for serving static files and directory listings.
std::string getMimeType(const std::string &filePath)
Get the MIME type based on the file extension.
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.
HttpFileserver()
Construct a new HttpFileserver object.
Forward declaration for potential routing needs.
const std::string & getPath() const
Get the parsed request path (without query string).
Represents an HTTP response object.
void writeChunk(const char *data, size_t length)
Send a chunk of the response body.
HttpResponse & set(const std::string &field, const std::string &value)
Set a generic header field.
void finish()
Finish the response (placeholder for potential finalization).
void start(int code, size_t contentLength, const std::string &contentType="application/octet-stream", const std::string &contentEncoding="")
Begin a streaming response by sending headers.
HttpResponse & sendSuccess(const nlohmann::json &data={}, const std::string &message="")
HttpResponse & sendError(int statusCode, const std::string &code, const std::string &message)
Abstract base class for storage access and file operations.
virtual bool isMounted() const =0
Check mounted.
virtual bool readFileString(const std::string &path, uint32_t startPosition, uint32_t length, std::string &buffer)=0
Read a file string into a memory buffer.
virtual size_t getFileSize(const std::string &path)=0
Get the size of a file.
virtual bool streamFile(const std::string &path, std::function< void(const uint8_t *, size_t)> chunkCallback)=0
Stream a file in chunks via callback.
virtual bool exists(const std::string &path)=0
Check whether a file or directory exists at the given path.
virtual bool mount()=0
Mount the underlying storage.
Delegates to user or system configuration.
#define STREAM_SEND_DELAY_MS
void sendError(HttpResponse &res, int statusCode, const std::string &code, const std::string &message)
Represents a match of a route against an incoming HTTP request.
std::string getMimeType(const std::string &filePath)
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.