From 5a0007f0837ee63079f00811280bc1c212d8349a Mon Sep 17 00:00:00 2001 From: Mike Kleshov Date: Thu, 16 Apr 2026 16:11:03 +0300 Subject: [PATCH] httpd: Add callbacks for GET header processing --- src/apps/http/httpd.c | 24 ++++++++++- src/include/lwip/apps/httpd.h | 67 ++++++++++++++++++++++++++++++ src/include/lwip/apps/httpd_opts.h | 31 ++++++++++++++ 3 files changed, 121 insertions(+), 1 deletion(-) diff --git a/src/apps/http/httpd.c b/src/apps/http/httpd.c index cf3abacf..8c74eb3b 100644 --- a/src/apps/http/httpd.c +++ b/src/apps/http/httpd.c @@ -2131,7 +2131,29 @@ http_parse_request(struct pbuf *inp, struct http_state *hs, struct altcp_pcb *pc } else #endif /* LWIP_HTTPD_SUPPORT_POST */ { - return http_find_file(hs, uri, is_09); +#if LWIP_HTTPD_HEADERS_BEFORE_FILE_OPEN + err_t err; + void *obj; + char replace_uri[LWIP_HTTPD_HEADERS_URI_REPLACE_LEN + 1]; + replace_uri[0] = 0; + obj = httpd_headers_before_file_open(crlf + 2, data_len - (crlf + 2 - data), + uri, replace_uri, + LWIP_HTTPD_HEADERS_URI_REPLACE_LEN); + if (replace_uri[0] != 0) { + uri = replace_uri; + } +#endif /* LWIP_HTTPD_HEADERS_BEFORE_FILE_OPEN */ + err = http_find_file(hs, uri, is_09); +#if LWIP_HTTPD_HEADERS_AFTER_FILE_OPEN + if (err == ERR_OK) { + httpd_headers_after_file_open(hs->handle, crlf + 2, data_len - (crlf + 2 - data) +#if LWIP_HTTPD_HEADERS_BEFORE_FILE_OPEN + , obj +#endif /* LWIP_HTTPD_HEADERS_BEFORE_FILE_OPEN */ + ); + } +#endif /* LWIP_HTTPD_HEADERS_AFTER_FILE_OPEN */ + return err; } } } else { diff --git a/src/include/lwip/apps/httpd.h b/src/include/lwip/apps/httpd.h index 1ecdd743..bb676021 100644 --- a/src/include/lwip/apps/httpd.h +++ b/src/include/lwip/apps/httpd.h @@ -242,6 +242,73 @@ void httpd_post_data_recved(void *connection, u16_t recved_len); #endif /* LWIP_HTTPD_SUPPORT_POST */ +#if LWIP_HTTPD_HEADERS_BEFORE_FILE_OPEN + +/** + * @ingroup httpd + * Callback to process HTTP headers before the file is opened. + * + * Called for each HTTP GET request after the request line is parsed but + * before fs_open() is called. This allows the application to inspect + * HTTP headers (cookies, authorization, etc.) and optionally replace the + * requested URI. + * + * The return value is an opaque object that will be passed to + * httpd_headers_after_file_open() if that callback is enabled. This can + * be used to pass parsed header data to the post-open callback without + * storing it globally. + * + * @param headers Pointer to the HTTP headers section (after request line). + * This points to the first character after the CRLF that + * terminates the request line (e.g., "Host: ...\r\n..."). + * @param headers_len Length of the headers data. + * @param uri The requested URI from the request line. + * @param replace_uri Buffer to optionally provide a different URI. If the + * first character is non-zero, this URI will be used + * instead of the original request URI. + * @param replace_uri_len Size of the replace_uri buffer. + * @return Opaque object pointer passed to httpd_headers_after_file_open(), + * or NULL if no object is needed. + */ +extern void* httpd_headers_before_file_open(const char* headers, u16_t headers_len, + const char *uri, char *replace_uri, + u16_t replace_uri_len); +#endif /* LWIP_HTTPD_HEADERS_BEFORE_FILE_OPEN */ + +#if LWIP_HTTPD_HEADERS_AFTER_FILE_OPEN +/* we have to prototype this struct here to make it available for the handler */ +struct fs_file; + +/** + * @ingroup httpd + * Callback to process HTTP headers after the file is opened. + * + * Called for each HTTP GET request after fs_open() succeeds and after CGI + * handling (if enabled). This allows the application to inspect HTTP headers + * (cookies, authorization, etc.) and optionally store state in the file + * structure for later use in SSI or dynamic file generation. + * + * The application can access file->state or file->pextension to retrieve or + * store per-request connection data that was initialized by fs_state_init(). + * + * @param file The opened file handle (from fs_open()). + * @param headers Pointer to the HTTP headers section (after request line). + * This points to the first character after the CRLF that + * terminates the request line (e.g., "Host: ...\r\n..."). + * @param headers_len Length of the headers data. + * @param state The opaque object pointer returned from + * httpd_headers_before_file_open(), if that callback is enabled. + * This can be used to pass parsed header data from the pre-open + * callback without storing it globally. + */ +extern void httpd_headers_after_file_open(struct fs_file *file, const char* headers, + u16_t headers_len +#if LWIP_HTTPD_HEADERS_BEFORE_FILE_OPEN + , void *state +#endif + ); +#endif /* LWIP_HTTPD_HEADERS_AFTER_FILE_OPEN */ + void httpd_init(void); #if HTTPD_ENABLE_HTTPS diff --git a/src/include/lwip/apps/httpd_opts.h b/src/include/lwip/apps/httpd_opts.h index 2b66e671..59257992 100644 --- a/src/include/lwip/apps/httpd_opts.h +++ b/src/include/lwip/apps/httpd_opts.h @@ -163,6 +163,37 @@ #define LWIP_HTTPD_MAX_TAG_INSERT_LEN 192 #endif +/** Set this to 1 to add a callback for HTTP headers processing. + * + * The httpd_headers_before_file_open() function is called for each HTTP GET + * request received, before the file is opened. + * The callback can parse headers and replace the URI for file to be opened. + * It can also pass an object to httpd_headers_after_file_open() if it is + * enabled (see below). + */ +#if !defined LWIP_HTTPD_HEADERS_BEFORE_FILE_OPEN || defined __DOXYGEN__ +#define LWIP_HTTPD_HEADERS_BEFORE_FILE_OPEN 0 +#endif + +/** Maximum length of the filename to replace the original URI in the + * httpd_headers_before_file_open() callback. + * This buffer is allocated on the stack. + */ +#if !defined LWIP_HTTPD_HEADERS_URI_REPLACE_LEN || defined __DOXYGEN__ +#define LWIP_HTTPD_HEADERS_URI_REPLACE_LEN 63 +#endif + +/** Set this to 1 to add a callback for HTTP headers processing. + * + * The httpd_headers_after_file_open() function is called for each HTTP GET + * request received, after the file is opened, and after CGI handling, + * if it is enabled. + * The callback can parse headers and store state in the file structure. + */ +#if !defined LWIP_HTTPD_HEADERS_AFTER_FILE_OPEN || defined __DOXYGEN__ +#define LWIP_HTTPD_HEADERS_AFTER_FILE_OPEN 0 +#endif + #if !defined LWIP_HTTPD_POST_MANUAL_WND || defined __DOXYGEN__ #define LWIP_HTTPD_POST_MANUAL_WND 0 #endif