mirror of
https://github.com/arendst/Tasmota.git
synced 2025-04-19 12:27:16 +00:00
Replace brotli compressed file serving with gzip (#23274)
* Replace brotli compressed file serving with gzip as it is better supported * Add HTTP_POST support
This commit is contained in:
parent
2999eed8b9
commit
cfe1cee4d3
@ -351,8 +351,52 @@ void be_httpserver_process_web_request(bvm *vm, http_queue_msg_t *msg) {
|
||||
// Push URI as argument
|
||||
be_pushstring(handler_vm, current_request->uri);
|
||||
|
||||
// Check if this is a POST request and handle POST data
|
||||
int arg_count = 1; // Start with 1 for the URI
|
||||
|
||||
if (current_request->method == HTTP_POST) {
|
||||
ESP_LOGI(TAG, "Processing POST request data");
|
||||
|
||||
// Get content length
|
||||
int content_len = current_request->content_len;
|
||||
ESP_LOGI(TAG, "POST content length: %d", content_len);
|
||||
|
||||
if (content_len > 0) {
|
||||
// Allocate buffer for POST data
|
||||
char *post_data = malloc(content_len + 1);
|
||||
if (post_data) {
|
||||
// Read POST data
|
||||
int received = httpd_req_recv(current_request, post_data, content_len);
|
||||
if (received > 0) {
|
||||
// Null-terminate the data
|
||||
post_data[received] = '\0';
|
||||
ESP_LOGI(TAG, "Received POST data: %s", post_data);
|
||||
|
||||
// Push POST data as second argument
|
||||
be_pushstring(handler_vm, post_data);
|
||||
arg_count = 2; // Now we have 2 arguments
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Failed to read POST data, received: %d", received);
|
||||
// Push nil as second argument
|
||||
be_pushnil(handler_vm);
|
||||
arg_count = 2;
|
||||
}
|
||||
free(post_data);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for POST data");
|
||||
// Push nil as second argument
|
||||
be_pushnil(handler_vm);
|
||||
arg_count = 2;
|
||||
}
|
||||
} else {
|
||||
// No content, push empty string as second argument
|
||||
be_pushstring(handler_vm, "");
|
||||
arg_count = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Call the Berry function
|
||||
int result = be_pcall(handler_vm, 1);
|
||||
int result = be_pcall(handler_vm, arg_count);
|
||||
|
||||
// Log stack state after call
|
||||
ESP_LOGI(TAG, "STACK: After be_pcall, stack top = %d, result = %d", be_top(handler_vm), result);
|
||||
@ -688,19 +732,36 @@ static int w_httpserver_start(bvm *vm) {
|
||||
// Register a URI handler
|
||||
static int w_httpserver_on(bvm *vm) {
|
||||
int top = be_top(vm);
|
||||
httpd_method_t http_method = HTTP_GET; // Default method
|
||||
|
||||
if (top < 2 || http_server == NULL) {
|
||||
be_raise(vm, "value_error", top < 2 ? "Missing arguments" : "Server not started");
|
||||
return 0;
|
||||
be_return(vm);
|
||||
}
|
||||
|
||||
if (!be_isstring(vm, 1) || !be_isfunction(vm, 2)) {
|
||||
be_raise(vm, "type_error", "String and function required");
|
||||
return 0;
|
||||
be_return(vm);
|
||||
}
|
||||
|
||||
// Check for optional method argument
|
||||
if (top >= 3) {
|
||||
if (!be_isstring(vm, 3)) {
|
||||
be_raise(vm, "type_error", "Method must be a string");
|
||||
be_return(vm);
|
||||
}
|
||||
const char *method_str = be_tostring(vm, 3);
|
||||
if (strcasecmp(method_str, "POST") == 0) {
|
||||
http_method = HTTP_POST;
|
||||
} else if (strcasecmp(method_str, "GET") != 0) {
|
||||
be_raise(vm, "value_error", "Method must be 'GET' or 'POST'");
|
||||
be_return(vm);
|
||||
}
|
||||
}
|
||||
|
||||
const char *uri = be_tostring(vm, 1);
|
||||
ESP_LOGI(TAG, "Registering handler for URI: %s", uri);
|
||||
ESP_LOGI(TAG, "Registering handler for URI: %s, Method: %s", uri,
|
||||
http_method == HTTP_GET ? "GET" : "POST");
|
||||
|
||||
// Find a free handler slot
|
||||
int slot = -1;
|
||||
@ -713,7 +774,7 @@ static int w_httpserver_on(bvm *vm) {
|
||||
|
||||
if (slot < 0) {
|
||||
be_raise(vm, "runtime_error", "No more handler slots available");
|
||||
return 0;
|
||||
be_return(vm);
|
||||
}
|
||||
|
||||
// Store handler info
|
||||
@ -729,7 +790,7 @@ static int w_httpserver_on(bvm *vm) {
|
||||
// Register the handler with ESP-IDF HTTP server
|
||||
httpd_uri_t http_uri = {
|
||||
.uri = uri,
|
||||
.method = HTTP_GET,
|
||||
.method = http_method,
|
||||
.handler = berry_handlers[slot],
|
||||
.user_ctx = NULL
|
||||
};
|
||||
@ -776,12 +837,6 @@ static int w_httpserver_stop(bvm *vm) {
|
||||
be_return (vm);
|
||||
}
|
||||
|
||||
// Get the server handle (for advanced usage)
|
||||
static int w_httpserver_get_handle(bvm *vm) {
|
||||
be_pushint(vm, (int)(intptr_t)http_server);
|
||||
be_return (vm);
|
||||
}
|
||||
|
||||
// Simple wrapper around httpd_resp_sendstr
|
||||
static int w_httpserver_send(bvm *vm) {
|
||||
int argc = be_top(vm);
|
||||
@ -832,7 +887,6 @@ module httpserver (scope: global, strings: weak) {
|
||||
start, func(w_httpserver_start)
|
||||
on, func(w_httpserver_on)
|
||||
send, func(w_httpserver_send)
|
||||
_handle, func(w_httpserver_get_handle)
|
||||
stop, func(w_httpserver_stop)
|
||||
process_queue, func(w_httpserver_process_queue)
|
||||
}
|
||||
|
@ -160,10 +160,11 @@ static void set_content_type_from_file(httpd_req_t *req, const char *filepath) {
|
||||
|
||||
static esp_err_t webfiles_handler(httpd_req_t *req) {
|
||||
char filepath[FILE_PATH_MAX];
|
||||
char brotli_filepath[FILE_PATH_MAX];
|
||||
char compressed_filepath[FILE_PATH_MAX];
|
||||
FILE *file = NULL;
|
||||
struct stat file_stat;
|
||||
bool use_brotli = false;
|
||||
bool use_compression = false;
|
||||
const char* compression_type = NULL; // Only "gzip" for for now
|
||||
|
||||
// Process any URL query parameters if needed
|
||||
char *query = strchr(req->uri, '?');
|
||||
@ -184,20 +185,24 @@ static esp_err_t webfiles_handler(httpd_req_t *req) {
|
||||
|
||||
ESP_LOGI(TAG, "Requested file: %s", filepath);
|
||||
|
||||
// Check if file is .html, .css, or .js and if a .br version exists
|
||||
// Check if file is .html, .css, .js, or .svg and if a compressed version exists
|
||||
const char *ext = strrchr(filepath, '.');
|
||||
if (ext && (strcasecmp(ext, ".html") == 0 || strcasecmp(ext, ".css") == 0 ||
|
||||
strcasecmp(ext, ".js") == 0 || strcasecmp(ext, ".svg") == 0)) {
|
||||
// Check if client supports Brotli
|
||||
char accept_encoding[64];
|
||||
if (httpd_req_get_hdr_value_str(req, "Accept-Encoding", accept_encoding, sizeof(accept_encoding)) == ESP_OK &&
|
||||
strstr(accept_encoding, "br") != NULL) {
|
||||
// Construct Brotli filepath
|
||||
snprintf(brotli_filepath, sizeof(brotli_filepath), "%s.br", filepath);
|
||||
if (stat(brotli_filepath, &file_stat) == 0 && S_ISREG(file_stat.st_mode)) {
|
||||
use_brotli = true;
|
||||
strcpy(filepath, brotli_filepath); // Use the .br file
|
||||
ESP_LOGI(TAG, "Found Brotli version: %s", filepath);
|
||||
|
||||
// Check what compression formats the client supports
|
||||
char accept_encoding[64] = {0};
|
||||
if (httpd_req_get_hdr_value_str(req, "Accept-Encoding", accept_encoding, sizeof(accept_encoding)) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Client supports compression: %s", accept_encoding);
|
||||
if (!use_compression && strstr(accept_encoding, "gzip") != NULL) {
|
||||
// Construct Gzip filepath
|
||||
snprintf(compressed_filepath, sizeof(compressed_filepath), "%s.gz", filepath);
|
||||
if (stat(compressed_filepath, &file_stat) == 0 && S_ISREG(file_stat.st_mode)) {
|
||||
use_compression = true;
|
||||
compression_type = "gzip";
|
||||
strcpy(filepath, compressed_filepath); // Use the .gz file
|
||||
ESP_LOGI(TAG, "Found Gzip version: %s", filepath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -224,20 +229,23 @@ static esp_err_t webfiles_handler(httpd_req_t *req) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Set content type based on file extension (use original path for MIME type if Brotli)
|
||||
// Set content type based on file extension (use original path for MIME type if compressed)
|
||||
char original_filepath[FILE_PATH_MAX];
|
||||
if (use_brotli) {
|
||||
// Strip .br for MIME type detection
|
||||
if (use_compression) {
|
||||
// Strip compression extension for MIME type detection
|
||||
strcpy(original_filepath, filepath);
|
||||
original_filepath[strlen(original_filepath) - 3] = '\0'; // Remove ".br"
|
||||
char* dot_pos = strrchr(original_filepath, '.');
|
||||
if (dot_pos) {
|
||||
*dot_pos = '\0'; // Remove compression extension
|
||||
}
|
||||
set_content_type_from_file(req, original_filepath);
|
||||
} else {
|
||||
set_content_type_from_file(req, filepath);
|
||||
}
|
||||
|
||||
// Set Brotli headers if applicable
|
||||
if (use_brotli) {
|
||||
httpd_resp_set_hdr(req, "Content-Encoding", "br");
|
||||
// Set compression headers if applicable
|
||||
if (use_compression) {
|
||||
httpd_resp_set_hdr(req, "Content-Encoding", compression_type);
|
||||
httpd_resp_set_hdr(req, "Vary", "Accept-Encoding");
|
||||
}
|
||||
|
||||
@ -260,7 +268,7 @@ static esp_err_t webfiles_handler(httpd_req_t *req) {
|
||||
|
||||
// Finish the HTTP response
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
ESP_LOGI(TAG, "File sent successfully (%d bytes, %s)", (int)total_sent, use_brotli ? "Brotli" : "uncompressed");
|
||||
ESP_LOGI(TAG, "File sent successfully (%d bytes, %s)", (int)total_sent, use_compression ? compression_type : "uncompressed");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user