added external reset callback for use with gpio extender;

fix some issues in web server
This commit is contained in:
Bogdan Pilyugin 2022-10-06 14:22:22 +02:00
parent 53e16bcacb
commit cc7ba0a36e
4 changed files with 494 additions and 481 deletions

View File

@ -113,4 +113,6 @@ esp_err_t StartOTA(void);
void StartSystemTimer(void); void StartSystemTimer(void);
uint32_t GetUpTime(void); uint32_t GetUpTime(void);
void RegEthReset(void (*eth_rst)(uint8_t level));
#endif /* MAIN_INCLUDE_NETTRANSPORT_H_ */ #endif /* MAIN_INCLUDE_NETTRANSPORT_H_ */

View File

@ -1,4 +1,4 @@
/* Copyright 2022 Bogdan Pilyugin /* Copyright 2022 Bogdan Pilyugin
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,8 +19,6 @@
* Description: * Description:
*/ */
#include "SystemConfiguration.h" #include "SystemConfiguration.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -37,9 +35,14 @@
#endif #endif
static const char *TAG = "EthTransport"; static const char *TAG = "EthTransport";
static bool isEthConn = false; static bool isEthConn = false;
static void (*eth_reset)(uint8_t level) = NULL;
void RegEthReset(void (*eth_rst)(uint8_t level))
{
eth_reset = eth_rst;
}
#if CONFIG_USE_SPI_ETHERNET #if CONFIG_USE_SPI_ETHERNET
esp_netif_t *eth_netif_spi[CONFIG_SPI_ETHERNETS_NUM] = { NULL }; esp_netif_t *eth_netif_spi[CONFIG_SPI_ETHERNETS_NUM] = { NULL };
@ -66,8 +69,6 @@ esp_netif_t* GetETHNetifAdapter(void)
#endif #endif
bool isETHConnected(void) bool isETHConnected(void)
{ {
return isEthConn; return isEthConn;
@ -122,7 +123,6 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
isEthConn = true; isEthConn = true;
} }
static void eth_init(void *pvParameter) static void eth_init(void *pvParameter)
{ {
#if CONFIG_USE_INTERNAL_ETHERNET #if CONFIG_USE_INTERNAL_ETHERNET
@ -161,13 +161,29 @@ static void eth_init(void *pvParameter)
#if CONFIG_USE_SPI_ETHERNET #if CONFIG_USE_SPI_ETHERNET
//Reset ethernet SPI device //Reset ethernet SPI device
#if CONFIG_ETH_SPI_PHY_RST0_GPIO >=0
gpio_set_level(CONFIG_ETH_SPI_PHY_RST0_GPIO, 0); gpio_set_level(CONFIG_ETH_SPI_PHY_RST0_GPIO, 0);
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(pdMS_TO_TICKS(10));
gpio_set_level(CONFIG_ETH_SPI_PHY_RST0_GPIO, 1); gpio_set_level(CONFIG_ETH_SPI_PHY_RST0_GPIO, 1);
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(pdMS_TO_TICKS(10));
#else
if (eth_reset)
{
eth_reset(0);
vTaskDelay(pdMS_TO_TICKS(10));
eth_reset(1);
vTaskDelay(pdMS_TO_TICKS(10));
}
else
{
ESP_LOGE(TAG, "ethernet chip reset pin not defined");
ESP_ERROR_CHECK(1);
}
#endif
// Create instance(s) of esp-netif for SPI Ethernet(s) // Create instance(s) of esp-netif for SPI Ethernet(s)
esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH(); esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH()
;
esp_netif_config_t cfg_spi = { esp_netif_config_t cfg_spi = {
.base = &esp_netif_config, .base = &esp_netif_config,
.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH .stack = ESP_NETIF_NETSTACK_DEFAULT_ETH
@ -183,7 +199,7 @@ static void eth_init(void *pvParameter)
strcat(strcpy(if_desc_str, "eth"), num_str); strcat(strcpy(if_desc_str, "eth"), num_str);
esp_netif_config.if_key = if_key_str; esp_netif_config.if_key = if_key_str;
esp_netif_config.if_desc = if_desc_str; esp_netif_config.if_desc = if_desc_str;
esp_netif_config.route_prio = ETH_PRIO-i; esp_netif_config.route_prio = ETH_PRIO - i;
eth_netif_spi[i] = esp_netif_new(&cfg_spi); eth_netif_spi[i] = esp_netif_new(&cfg_spi);
} }
@ -301,7 +317,7 @@ static void eth_init(void *pvParameter)
else else
{ {
ESP_ERROR_CHECK(esp_eth_ioctl(eth_handle_spi[i], ETH_CMD_S_MAC_ADDR, (uint8_t[] ) { ESP_ERROR_CHECK(esp_eth_ioctl(eth_handle_spi[i], ETH_CMD_S_MAC_ADDR, (uint8_t[] ) {
0x02, 0x00, 0x00, 0x12, 0x34, 0x56 + i})); 0x02, 0x00, 0x00, 0x12, 0x34, 0x56 + i }));
} }
// attach Ethernet driver to TCP/IP stack // attach Ethernet driver to TCP/IP stack
ESP_ERROR_CHECK(esp_netif_attach(eth_netif_spi[i], esp_eth_new_netif_glue(eth_handle_spi[i]))); ESP_ERROR_CHECK(esp_netif_attach(eth_netif_spi[i], esp_eth_new_netif_glue(eth_handle_spi[i])));
@ -330,10 +346,8 @@ static void eth_init(void *pvParameter)
vTaskDelete(NULL); vTaskDelete(NULL);
} }
void EthStart(void) void EthStart(void)
{ {
xTaskCreate(eth_init, "EthInitTask", 1024 * 4, (void*) 0, 3, NULL); xTaskCreate(eth_init, "EthInitTask", 1024 * 4, (void*) 0, 3, NULL);
} }

View File

@ -1,468 +1,465 @@
/*! Copyright 2022 Bogdan Pilyugin /*! Copyright 2022 Bogdan Pilyugin
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* *
* \file HTTPServer.c * \file HTTPServer.c
* \version 1.0 * \version 1.0
* \date 2022-08-14 * \date 2022-08-14
* \author Bogdan Pilyugin * \author Bogdan Pilyugin
* \brief * \brief
* \details * \details
* \copyright Apache License, Version 2.0 * \copyright Apache License, Version 2.0
*/ */
#include "HTTPServer.h" #include "HTTPServer.h"
#include "sdkconfig.h" #include "sdkconfig.h"
const char GZIP_SIGN[] = { 0x1f, 0x8b, 0x08 }; const char GZIP_SIGN[] = { 0x1f, 0x8b, 0x08 };
static esp_err_t GETHandler(httpd_req_t *req); static esp_err_t GETHandler(httpd_req_t *req);
static esp_err_t CheckAuth(httpd_req_t *req); static esp_err_t CheckAuth(httpd_req_t *req);
/* Max length a file path can have on storage */ /* Max length a file path can have on storage */
#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + CONFIG_SPIFFS_OBJ_NAME_LEN) #define FILE_PATH_MAX (ESP_VFS_PATH_MAX + CONFIG_SPIFFS_OBJ_NAME_LEN)
/* Max size of an individual file. Make sure this /* Max size of an individual file. Make sure this
* value is same as that set in upload_script.html */ * value is same as that set in upload_script.html */
#define MAX_FILE_SIZE (200*1024) // 200 KB #define MAX_FILE_SIZE (200*1024) // 200 KB
#define MAX_FILE_SIZE_STR "200KB" #define MAX_FILE_SIZE_STR "200KB"
/* Scratch buffer size */ /* Scratch buffer size */
#define SCRATCH_BUFSIZE 8192 #define SCRATCH_BUFSIZE 8192
#define AUTH_DATA_MAX_LENGTH 16 #define AUTH_DATA_MAX_LENGTH 16
struct file_server_data struct file_server_data
{ {
/* Base path of file storage */ /* Base path of file storage */
char base_path[ESP_VFS_PATH_MAX + 1]; char base_path[ESP_VFS_PATH_MAX + 1];
/* Scratch buffer for temporary storage during file transfer */ /* Scratch buffer for temporary storage during file transfer */
char scratch[SCRATCH_BUFSIZE]; char scratch[SCRATCH_BUFSIZE];
/* Pointer to external POST handler*/ /* Pointer to external POST handler*/
}; };
struct file_server_data *server_data = NULL; struct file_server_data *server_data = NULL;
httpd_handle_t server = NULL; httpd_handle_t server = NULL;
static const char *TAG = "HTTPServer"; static const char *TAG = "HTTPServer";
static esp_err_t CheckAuth(httpd_req_t *req) static esp_err_t CheckAuth(httpd_req_t *req)
{ {
unsigned char pass[18] = { 0 }; //max length of login:password decoded string unsigned char pass[18] = { 0 }; //max length of login:password decoded string
unsigned char inp[31]; //max length of login:password coded string plus Basic unsigned char inp[31]; //max length of login:password coded string plus Basic
const char keyword1[] = "Basic "; const char keyword1[] = "Basic ";
const int keyword1len = sizeof(keyword1) - 1; const int keyword1len = sizeof(keyword1) - 1;
if (httpd_req_get_hdr_value_len(req, "Authorization") > 31) if (httpd_req_get_hdr_value_len(req, "Authorization") > 31)
{ {
httpd_resp_set_hdr(req, "Connection", "close"); httpd_resp_set_hdr(req, "Connection", "close");
httpd_resp_send_err(req, HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE, "Authorization field value is too large"); httpd_resp_send_err(req, HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE, "Authorization field value is too large");
return ESP_FAIL; return ESP_FAIL;
} }
httpd_req_get_hdr_value_str(req, "Authorization", (char*) inp, 31); httpd_req_get_hdr_value_str(req, "Authorization", (char*) inp, 31);
unsigned char *pt = memmem(inp, sizeof(inp), keyword1, keyword1len); unsigned char *pt = memmem(inp, sizeof(inp), keyword1, keyword1len);
if (pt) if (pt)
{ {
pt += keyword1len; pt += keyword1len;
#if HTTP_SERVER_DEBUG_LEVEL > 0 #if HTTP_SERVER_DEBUG_LEVEL > 0
ESP_LOGI(TAG, "Authorization string is:%s", pt); ESP_LOGI(TAG, "Authorization string is:%s", pt);
#endif #endif
size_t l; size_t l;
mbedtls_base64_decode(pass, (size_t) sizeof(pass), &l, pt, strlen((const char*) pt)); mbedtls_base64_decode(pass, (size_t) sizeof(pass), &l, pt, strlen((const char*) pt));
#if HTTP_SERVER_DEBUG_LEVEL > 0 #if HTTP_SERVER_DEBUG_LEVEL > 0
ESP_LOGI(TAG, "Authorization decoded string is:%s", pass); ESP_LOGI(TAG, "Authorization decoded string is:%s", pass);
#endif #endif
strcpy((char*) inp, GetSysConf()->SysName); //buffer inp reused for login:pass check strcpy((char*) inp, GetSysConf()->SysName); //buffer inp reused for login:pass check
strcat((char*) inp, (char*) ":"); strcat((char*) inp, (char*) ":");
strcat((char*) inp, GetSysConf()->SysPass); strcat((char*) inp, GetSysConf()->SysPass);
#if HTTP_SERVER_DEBUG_LEVEL > 0 #if HTTP_SERVER_DEBUG_LEVEL > 0
ESP_LOGI(TAG, "Reference auth data is %s", inp); ESP_LOGI(TAG, "Reference auth data is %s", inp);
#endif #endif
} }
if (pt == NULL || strcmp((const char*) inp, (char*) pass)) if (pt == NULL || strcmp((const char*) inp, (char*) pass))
{ {
httpd_resp_set_hdr(req, "WWW-Authenticate", "Basic"); httpd_resp_set_hdr(req, "WWW-Authenticate", "Basic");
//httpd_resp_set_hdr(req, "Connection", "keep-alive"); //httpd_resp_set_hdr(req, "Connection", "keep-alive");
httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "This page requires authorization"); httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "This page requires authorization");
return ESP_FAIL; return ESP_FAIL;
} }
return ESP_OK; return ESP_OK;
} }
#define IS_FILE_EXT(filename, ext) \ #define IS_FILE_EXT(filename, ext) \
(strcasecmp(&filename[strlen(filename) - sizeof(ext) + 1], ext) == 0) (strcasecmp(&filename[strlen(filename) - sizeof(ext) + 1], ext) == 0)
/* Set HTTP response content type according to file extension */ /* Set HTTP response content type according to file extension */
static esp_err_t set_content_type_from_file(httpd_req_t *req, static esp_err_t set_content_type_from_file(httpd_req_t *req,
const char *filename) const char *filename)
{ {
if (IS_FILE_EXT(filename, ".pdf")) if (IS_FILE_EXT(filename, ".pdf"))
{ {
return httpd_resp_set_type(req, "application/pdf"); return httpd_resp_set_type(req, "application/pdf");
} }
else if (IS_FILE_EXT(filename, ".html")) else if (IS_FILE_EXT(filename, ".html"))
{ {
return httpd_resp_set_type(req, "text/html"); return httpd_resp_set_type(req, "text/html");
} }
else if (IS_FILE_EXT(filename, ".jpeg")) else if (IS_FILE_EXT(filename, ".jpeg"))
{ {
return httpd_resp_set_type(req, "image/jpeg"); return httpd_resp_set_type(req, "image/jpeg");
} }
else if (IS_FILE_EXT(filename, ".png")) else if (IS_FILE_EXT(filename, ".png"))
{ {
return httpd_resp_set_type(req, "image/png"); return httpd_resp_set_type(req, "image/png");
} }
else if (IS_FILE_EXT(filename, ".ico")) else if (IS_FILE_EXT(filename, ".ico"))
{ {
return httpd_resp_set_type(req, "image/x-icon"); return httpd_resp_set_type(req, "image/x-icon");
} }
else if (IS_FILE_EXT(filename, ".css")) else if (IS_FILE_EXT(filename, ".css"))
{ {
return httpd_resp_set_type(req, "text/css"); return httpd_resp_set_type(req, "text/css");
} }
else if (IS_FILE_EXT(filename, ".woff2")) else if (IS_FILE_EXT(filename, ".woff2"))
{ {
return httpd_resp_set_type(req, "font/woff2"); return httpd_resp_set_type(req, "font/woff2");
} }
/* This is a limited set only */ /* This is a limited set only */
/* For any other type always set as plain text */ /* For any other type always set as plain text */
return httpd_resp_set_type(req, "text/plain"); return httpd_resp_set_type(req, "text/plain");
} }
/* Copies the full path into destination buffer and returns /* Copies the full path into destination buffer and returns
* pointer to path (skipping the preceding base path) */ * pointer to path (skipping the preceding base path) */
static const char* get_path_from_uri(char *dest, const char *base_path, static const char* get_path_from_uri(char *dest, const char *base_path,
const char *uri, const char *uri,
size_t destsize) size_t destsize)
{ {
const size_t base_pathlen = strlen(base_path); const size_t base_pathlen = strlen(base_path);
size_t pathlen = strlen(uri); size_t pathlen = strlen(uri);
const char *quest = strchr(uri, '?'); const char *quest = strchr(uri, '?');
if (quest) if (quest)
{ {
pathlen = MIN(pathlen, quest - uri); pathlen = MIN(pathlen, quest - uri);
} }
const char *hash = strchr(uri, '#'); const char *hash = strchr(uri, '#');
if (hash) if (hash)
{ {
pathlen = MIN(pathlen, hash - uri); pathlen = MIN(pathlen, hash - uri);
} }
if (base_pathlen + pathlen + 1 > destsize) if (base_pathlen + pathlen + 1 > destsize)
{ {
/* Full path string won't fit into destination buffer */ /* Full path string won't fit into destination buffer */
return NULL; return NULL;
} }
/* Construct full path (base + path) */ /* Construct full path (base + path) */
strcpy(dest, base_path); strcpy(dest, base_path);
strlcpy(dest + base_pathlen, uri, pathlen + 1); strlcpy(dest + base_pathlen, uri, pathlen + 1);
/* Return pointer to path, skipping the base */ /* Return pointer to path, skipping the base */
return dest + base_pathlen; return dest + base_pathlen;
} }
static esp_err_t POSTHandler(httpd_req_t *req) static esp_err_t POSTHandler(httpd_req_t *req)
{ {
#if HTTP_SERVER_DEBUG_LEVEL > 0 #if HTTP_SERVER_DEBUG_LEVEL > 0
ESP_LOGI(TAG, "POST request handle"); ESP_LOGI(TAG, "POST request handle");
#endif #endif
char *buf = ((struct file_server_data*) req->user_ctx)->scratch; char *buf = ((struct file_server_data*) req->user_ctx)->scratch;
int received; int received;
int remaining = req->content_len; int remaining = req->content_len;
buf[req->content_len] = 0x00; buf[req->content_len] = 0x00;
HTTP_IO_RESULT http_res; HTTP_IO_RESULT http_res;
while (remaining > 0) while (remaining > 0)
{ {
#if HTTP_SERVER_DEBUG_LEVEL > 0 #if HTTP_SERVER_DEBUG_LEVEL > 0
ESP_LOGI(TAG, "Remaining size : %d", remaining); ESP_LOGI(TAG, "Remaining size : %d", remaining);
#endif #endif
/* Receive the file part by part into a buffer */ /* Receive the file part by part into a buffer */
if ((received = httpd_req_recv(req, buf, if ((received = httpd_req_recv(req, buf,
MIN(remaining, SCRATCH_BUFSIZE))) <= 0) MIN(remaining, SCRATCH_BUFSIZE))) <= 0)
{ {
if (received == HTTPD_SOCK_ERR_TIMEOUT) if (received == HTTPD_SOCK_ERR_TIMEOUT)
{ {
/* Retry if timeout occurred */ /* Retry if timeout occurred */
continue; continue;
} }
/* In case of unrecoverable error*/ /* In case of unrecoverable error*/
ESP_LOGE(TAG, "File reception failed!"); ESP_LOGE(TAG, "File reception failed!");
/* Respond with 500 Internal Server Error */ /* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR,
"Failed to receive file"); "Failed to receive file");
return ESP_FAIL; return ESP_FAIL;
} }
/* Write buffer content to file on storage */ /* Write buffer content to file on storage */
if (received) if (received)
{ {
char filepath[FILE_PATH_MAX]; char filepath[FILE_PATH_MAX];
const char *filename = get_path_from_uri(filepath, const char *filename = get_path_from_uri(filepath,
((struct file_server_data*) req->user_ctx)->base_path, ((struct file_server_data*) req->user_ctx)->base_path,
req->uri, req->uri,
sizeof(filepath)); sizeof(filepath));
http_res = HTTPPostApp(req, filename, buf); http_res = HTTPPostApp(req, filename, buf);
if (http_res == HTTP_IO_DONE) if (http_res == HTTP_IO_DONE)
return GETHandler(req); return GETHandler(req);
else if (http_res == HTTP_IO_REDIRECT) else if (http_res == HTTP_IO_REDIRECT)
{ {
httpd_resp_set_status(req, "307 Temporary Redirect"); httpd_resp_set_status(req, "307 Temporary Redirect");
httpd_resp_set_hdr(req, "Location", filename); httpd_resp_set_hdr(req, "Location", filename);
httpd_resp_send(req, NULL, 0); // Response body can be empty httpd_resp_send(req, NULL, 0); // Response body can be empty
#if HTTP_SERVER_DEBUG_LEVEL > 0 #if HTTP_SERVER_DEBUG_LEVEL > 0
ESP_LOGI(TAG, "Redirect request from POST"); ESP_LOGI(TAG, "Redirect request from POST");
#endif #endif
return ESP_OK; return ESP_OK;
} }
else if (http_res == HTTP_IO_DONE_NOREFRESH) else if (http_res == HTTP_IO_DONE_NOREFRESH)
{ {
httpd_resp_set_status(req, HTTPD_204); httpd_resp_set_status(req, HTTPD_204);
httpd_resp_send(req, NULL, 0); // Response body can be empty httpd_resp_send(req, NULL, 0); // Response body can be empty
return ESP_OK; return ESP_OK;
} }
} }
/* Keep track of remaining size of /* Keep track of remaining size of
* the file left to be uploaded */ * the file left to be uploaded */
remaining -= received; remaining -= received;
} }
return ESP_OK; return ESP_OK;
} }
static esp_err_t GETHandler(httpd_req_t *req) static esp_err_t GETHandler(httpd_req_t *req)
{ {
#if HTTP_SERVER_DEBUG_LEVEL > 0 #if HTTP_SERVER_DEBUG_LEVEL > 0
ESP_LOGI(TAG, "GET request handle"); ESP_LOGI(TAG, "GET request handle");
#endif #endif
char filepath[FILE_PATH_MAX]; char filepath[FILE_PATH_MAX];
espfs_file_t *file; espfs_file_t *file;
struct espfs_stat_t stat; struct espfs_stat_t stat;
bool isDynamicVars = false; bool isDynamicVars = false;
const char *filename = get_path_from_uri(filepath, const char *filename = get_path_from_uri(filepath,
((struct file_server_data*) req->user_ctx)->base_path, ((struct file_server_data*) req->user_ctx)->base_path,
req->uri, req->uri,
sizeof(filepath)); sizeof(filepath));
if (!filename) if (!filename)
{ {
ESP_LOGE(TAG, "Filename is too long"); ESP_LOGE(TAG, "Filename is too long");
/* Respond with 500 Internal Server Error */ /* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR,
"Filename too long"); "Filename too long");
return ESP_FAIL; return ESP_FAIL;
} }
/* Redirect request to /index.html */ /* Redirect request to /index.html */
if (filename[strlen(filename) - 1] == '/') if (filename[strlen(filename) - 1] == '/')
{ {
httpd_resp_set_status(req, "307 Temporary Redirect"); httpd_resp_set_status(req, "307 Temporary Redirect");
httpd_resp_set_hdr(req, "Location", "/index.html"); httpd_resp_set_hdr(req, "Location", "/index.html");
httpd_resp_send(req, NULL, 0); // Response body can be empty httpd_resp_send(req, NULL, 0); // Response body can be empty
#if HTTP_SERVER_DEBUG_LEVEL > 0 #if HTTP_SERVER_DEBUG_LEVEL > 0
ESP_LOGI(TAG, "Redirect request to /index.html"); ESP_LOGI(TAG, "Redirect request to /index.html");
#endif #endif
return ESP_OK; return ESP_OK;
} }
//check auth for all files except status.json //check auth for all files except status.json
if (strcmp(filename, "/status.json")) if (strcmp(filename, "/status.json"))
{ {
if (CheckAuth(req) != ESP_OK) if (CheckAuth(req) != ESP_OK)
{ {
return ESP_FAIL; return ESP_FAIL;
} }
} }
//open file //open file
file = espfs_fopen(fs, filepath); file = espfs_fopen(fs, filepath);
if (!file) if (!file)
{ {
ESP_LOGE(TAG, "Failed to read existing file : %s", filepath); httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File not found");
/* Respond with 500 Internal Server Error */ return ESP_FAIL;
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, }
"Failed to read existing file"); //get file info
return ESP_FAIL; espfs_stat(fs, filepath, &stat);
}
//get file info #if HTTP_SERVER_DEBUG_LEVEL > 0
espfs_stat(fs, filepath, &stat); ESP_LOGI(TAG, "Sending file : %s (%d bytes)...", filename,
stat.size);
#if HTTP_SERVER_DEBUG_LEVEL > 0 #endif
ESP_LOGI(TAG, "Sending file : %s (%d bytes)...", filename, //OutputDisplay((char*) filepath);
stat.size); set_content_type_from_file(req, filename);
#endif /* Retrieve the pointer to scratch buffer for temporary storage */
//OutputDisplay((char*) filepath); char *chunk = ((struct file_server_data*) req->user_ctx)->scratch;
set_content_type_from_file(req, filename); uint32_t readBytes, fileSize;
/* Retrieve the pointer to scratch buffer for temporary storage */ fileSize = stat.size;
char *chunk = ((struct file_server_data*) req->user_ctx)->scratch; char *buf = (char*) malloc(fileSize);
uint32_t readBytes, fileSize; if (buf)
fileSize = stat.size; {
char *buf = (char*) malloc(fileSize); readBytes = espfs_fread(file, buf, fileSize);
if (buf) }
{ else
readBytes = espfs_fread(file, buf, fileSize); {
} ESP_LOGE(TAG, "Failed to allocate memory");
else /* Respond with 500 Internal Server Error */
{ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR,
ESP_LOGE(TAG, "Failed to allocate memory"); "Out of memory");
/* Respond with 500 Internal Server Error */ espfs_fclose(file);
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, return ESP_FAIL;
"Out of memory"); }
espfs_fclose(file);
return ESP_FAIL; if (memmem(buf, 3, GZIP_SIGN, 3))
} {
httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
if (memmem(buf, 3, GZIP_SIGN, 3)) httpd_resp_set_hdr(req, "Cache-Control", "max-age=600");
{ }
httpd_resp_set_hdr(req, "Content-Encoding", "gzip");
httpd_resp_set_hdr(req, "Cache-Control", "max-age=600"); if (IS_FILE_EXT(filename, ".html") || IS_FILE_EXT(filename, ".json"))
} isDynamicVars = true;
if (IS_FILE_EXT(filename, ".html") || IS_FILE_EXT(filename, ".json")) int pt = 0;
isDynamicVars = true; do
{
int pt = 0; readBytes = 0;
do while (pt < fileSize && readBytes < (SCRATCH_BUFSIZE - 64))
{ {
readBytes = 0; if (buf[pt] == '~' && isDynamicVars)
while (pt < fileSize && readBytes < (SCRATCH_BUFSIZE - 64)) {
{ int k = 0;
if (buf[pt] == '~' && isDynamicVars) char DynVarName[16];
{ while (pt < fileSize && k < 16 && (buf[++pt] != '~'))
int k = 0; DynVarName[k++] = buf[pt];
char DynVarName[16]; if (buf[pt] == '~')
while (pt < fileSize && k < 16 && (buf[++pt] != '~')) { //got valid dynamic variable name
DynVarName[k++] = buf[pt]; DynVarName[k] = 0x00;
if (buf[pt] == '~') readBytes += HTTPPrint(req, &chunk[readBytes], DynVarName);
{ //got valid dynamic variable name pt++;
DynVarName[k] = 0x00; }
readBytes += HTTPPrint(req, &chunk[readBytes], DynVarName); }
pt++; else
} chunk[readBytes++] = buf[pt++];
} }
else if (readBytes != 0)
chunk[readBytes++] = buf[pt++]; {
} /* Send the buffer contents as HTTP response chunk */
if (readBytes != 0) #if HTTP_SERVER_DEBUG_LEVEL > 0
{ ESP_LOGI(TAG, "Write to HTTPserv resp %d", readBytes);
/* Send the buffer contents as HTTP response chunk */ #endif
#if HTTP_SERVER_DEBUG_LEVEL > 0 if (httpd_resp_send_chunk(req, chunk, readBytes) != ESP_OK)
ESP_LOGI(TAG, "Write to HTTPserv resp %d", readBytes); {
#endif ESP_LOGE(TAG, "File sending failed!");
if (httpd_resp_send_chunk(req, chunk, readBytes) != ESP_OK) /* Abort sending file */
{ httpd_resp_sendstr_chunk(req, NULL);
ESP_LOGE(TAG, "File sending failed!"); /* Respond with 500 Internal Server Error */
/* Abort sending file */ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR,
httpd_resp_sendstr_chunk(req, NULL); "Failed to send file");
/* Respond with 500 Internal Server Error */ free(buf);
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, espfs_fclose(file);
"Failed to send file"); return ESP_FAIL;
free(buf); }
espfs_fclose(file);
return ESP_FAIL; }
} /* Keep looping till the whole file is sent */
}
} while (readBytes != 0);
/* Keep looping till the whole file is sent */ /* Close file after sending complete */
} espfs_fclose(file);
while (readBytes != 0); #if HTTP_SERVER_DEBUG_LEVEL > 0
/* Close file after sending complete */ ESP_LOGI(TAG, "File sending complete");
espfs_fclose(file); #endif
#if HTTP_SERVER_DEBUG_LEVEL > 0 /* Respond with an empty chunk to signal HTTP response completion */
ESP_LOGI(TAG, "File sending complete"); httpd_resp_send_chunk(req, NULL, 0);
#endif free(buf);
/* Respond with an empty chunk to signal HTTP response completion */ return ESP_OK;
httpd_resp_send_chunk(req, NULL, 0); }
free(buf);
return ESP_OK; static httpd_handle_t start_webserver(void)
} {
httpd_handle_t server = NULL;
static httpd_handle_t start_webserver(void) httpd_config_t config = HTTPD_DEFAULT_CONFIG();
{ config.lru_purge_enable = true;
httpd_handle_t server = NULL; config.uri_match_fn = httpd_uri_match_wildcard;
httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.max_open_sockets = 3;
config.lru_purge_enable = true;
config.uri_match_fn = httpd_uri_match_wildcard; // Start the httpd server
config.max_open_sockets = 3; ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
if (httpd_start(&server, &config) == ESP_OK)
// Start the httpd server {
ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port); // Set URI handlers
if (httpd_start(&server, &config) == ESP_OK) ESP_LOGI(TAG, "Registering URI handlers");
{ /* URI handler for GET request */
// Set URI handlers httpd_uri_t get = { .uri = "/*",
ESP_LOGI(TAG, "Registering URI handlers"); .method = HTTP_GET,
/* URI handler for GET request */ .handler = GETHandler,
httpd_uri_t get = { .uri = "/*", .user_ctx = server_data // Pass server data as context
.method = HTTP_GET, };
.handler = GETHandler, httpd_register_uri_handler(server, &get);
.user_ctx = server_data // Pass server data as context
}; /* URI handler for POST request */
httpd_register_uri_handler(server, &get); httpd_uri_t post = { .uri = "/*",
.method = HTTP_POST,
/* URI handler for POST request */ .handler = POSTHandler,
httpd_uri_t post = { .uri = "/*", .user_ctx = server_data // Pass server data as context
.method = HTTP_POST, };
.handler = POSTHandler, httpd_register_uri_handler(server, &post);
.user_ctx = server_data // Pass server data as context return server;
}; }
httpd_register_uri_handler(server, &post); ESP_LOGI(TAG, "Error starting server!");
return server; return NULL;
} }
ESP_LOGI(TAG, "Error starting server!");
return NULL; static void stop_webserver(httpd_handle_t server)
} {
// Stop the httpd server
static void stop_webserver(httpd_handle_t server) httpd_stop(server);
{ }
// Stop the httpd server
httpd_stop(server); static void reconnect_handler(void *arg, esp_event_base_t event_base,
} int32_t event_id,
void *event_data)
static void reconnect_handler(void *arg, esp_event_base_t event_base, {
int32_t event_id, httpd_handle_t *server = (httpd_handle_t*) arg;
void *event_data) if (*server)
{ {
httpd_handle_t *server = (httpd_handle_t*) arg; ESP_LOGI(TAG, "Any adapter got new IP. Restart web server.");
if (*server) stop_webserver(*server);
{ *server = start_webserver();
ESP_LOGI(TAG, "Any adapter got new IP. Restart web server."); }
stop_webserver(*server); }
*server = start_webserver();
} /* Function to start the file server */
} esp_err_t start_file_server(void)
{
/* Function to start the file server */ if (server_data)
esp_err_t start_file_server(void) {
{ ESP_LOGE(TAG, "File server already started");
if (server_data) return ESP_ERR_INVALID_STATE;
{ }
ESP_LOGE(TAG, "File server already started"); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &reconnect_handler, &server));
return ESP_ERR_INVALID_STATE; ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &reconnect_handler, &server));
}
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &reconnect_handler, &server)); /* Allocate memory for server data */
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &reconnect_handler, &server)); server_data = calloc(1, sizeof(struct file_server_data));
if (!server_data)
/* Allocate memory for server data */ {
server_data = calloc(1, sizeof(struct file_server_data)); ESP_LOGE(TAG, "Failed to allocate memory for server data");
if (!server_data) return ESP_ERR_NO_MEM;
{ }
ESP_LOGE(TAG, "Failed to allocate memory for server data"); strlcpy(server_data->base_path, "/", sizeof("/"));
return ESP_ERR_NO_MEM; server = start_webserver();
} return ESP_OK;
strlcpy(server_data->base_path, "/", sizeof("/")); }
server = start_webserver();
return ESP_OK;
}

View File

@ -169,7 +169,7 @@ if(GetSysConf()->wifiSettings.Flags1.bIsAP)
static void InitSysIO(void) static void InitSysIO(void)
{ {
#if (FUNCTIONAL_BUTTON_GPIO >= 0) #if (MAIN_FUNCTIONAL_BUTTON_GPIO >= 0)
gpio_pad_select_gpio(MAIN_FUNCTIONAL_BUTTON_GPIO); gpio_pad_select_gpio(MAIN_FUNCTIONAL_BUTTON_GPIO);
gpio_set_direction(MAIN_FUNCTIONAL_BUTTON_GPIO, GPIO_MODE_INPUT); gpio_set_direction(MAIN_FUNCTIONAL_BUTTON_GPIO, GPIO_MODE_INPUT);
gpio_set_pull_mode(MAIN_FUNCTIONAL_BUTTON_GPIO, GPIO_PULLUP_ONLY); gpio_set_pull_mode(MAIN_FUNCTIONAL_BUTTON_GPIO, GPIO_PULLUP_ONLY);