|
@@ -1,9 +1,11 @@
|
|
|
#define MODULE "httpd"
|
|
|
+#define DEBUG 1
|
|
|
|
|
|
#include "common.h"
|
|
|
#include "fw.h"
|
|
|
#include "httpd.h"
|
|
|
#include "config.h"
|
|
|
+#include "boardinfo_esp.h"
|
|
|
|
|
|
#include <incbin.h>
|
|
|
#include <unzipLIB.h>
|
|
@@ -209,7 +211,7 @@ static esp_err_t httpd_send_plain(httpd_req_t *req,
|
|
|
|
|
|
const char * const refresher = refresher_buf ? refresher_buf : "";
|
|
|
const char * const uncacher = (flags & HSP_UNCACHE)
|
|
|
- ? "Clear-Site-Data: \"cache\"\r\n" : "";
|
|
|
+ ? "Clear-Site-Data: \"cache\"\r\n" : "";
|
|
|
|
|
|
if (redirect) {
|
|
|
/* \0 -> \n so don't include it */
|
|
@@ -295,6 +297,17 @@ static esp_err_t httpd_err_enomem(httpd_req_t *req)
|
|
|
return HTTP_ERR(req, 503, "Out of memory");
|
|
|
}
|
|
|
|
|
|
+static esp_err_t httpd_err_not_post(httpd_req_t *req)
|
|
|
+{
|
|
|
+ return HTTP_ERR(req, 405, "Only POST allowed");
|
|
|
+}
|
|
|
+
|
|
|
+#define HTTPD_ASSERT_POST(req) \
|
|
|
+ do { \
|
|
|
+ if ((req)->method != HTTP_POST) \
|
|
|
+ return httpd_err_not_post(req); \
|
|
|
+ } while (0)
|
|
|
+
|
|
|
static esp_err_t httpd_update_done(httpd_req_t *req, const char *what, int err)
|
|
|
{
|
|
|
char *response = NULL;
|
|
@@ -328,6 +341,8 @@ static esp_err_t httpd_firmware_update(httpd_req_t *req)
|
|
|
{
|
|
|
int rv;
|
|
|
|
|
|
+ HTTPD_ASSERT_POST(req);
|
|
|
+
|
|
|
/* XXX: use httpd_fopen_read() here */
|
|
|
rv = firmware_update_start((read_func_t)httpd_req_recv, (token_t)req, false);
|
|
|
if (!rv)
|
|
@@ -360,6 +375,103 @@ static esp_err_t httpd_set_config(httpd_req_t *req, const char *query)
|
|
|
return httpd_update_done(req, "Configuration", rv1 ? rv1 : rv2);
|
|
|
}
|
|
|
|
|
|
+static inline bool is_eol(int c)
|
|
|
+{
|
|
|
+ return c == EOF || c == '\0' || c == '\r' || c == '\n';
|
|
|
+}
|
|
|
+
|
|
|
+static esp_err_t httpd_set_board_rev(httpd_req_t *req)
|
|
|
+{
|
|
|
+ FILE *f = NULL;
|
|
|
+ static const char rev_prefix[] = "max80.hw.ver";
|
|
|
+ static const char rev_valid[] = "MAX80 v";
|
|
|
+ char *rev_str;
|
|
|
+ int err = Z_DATA_ERROR;
|
|
|
+ enum sbr_parse_state {
|
|
|
+ ps_start,
|
|
|
+ ps_prefix,
|
|
|
+ ps_string,
|
|
|
+ ps_skipline
|
|
|
+ };
|
|
|
+ enum sbr_parse_state state;
|
|
|
+ const char *match_ptr = NULL;
|
|
|
+ char *p = NULL;
|
|
|
+ int c;
|
|
|
+
|
|
|
+ HTTPD_ASSERT_POST(req);
|
|
|
+
|
|
|
+ rev_str = malloc(sizeof board_info.version_str);
|
|
|
+ if (!rev_str)
|
|
|
+ return httpd_err_enomem(req);
|
|
|
+
|
|
|
+ f = httpd_fopen_read(req);
|
|
|
+ if (!f) {
|
|
|
+ free(rev_str);
|
|
|
+ return HTTP_ERR(req, 500, "Unable to get request handle");
|
|
|
+ }
|
|
|
+
|
|
|
+ state = ps_start;
|
|
|
+
|
|
|
+ do {
|
|
|
+ bool eol;
|
|
|
+
|
|
|
+ c = getc(f);
|
|
|
+ eol = is_eol(c);
|
|
|
+
|
|
|
+ switch (state) {
|
|
|
+ case ps_start:
|
|
|
+ match_ptr = rev_prefix;
|
|
|
+ state = ps_prefix;
|
|
|
+ /* fall through */
|
|
|
+
|
|
|
+ case ps_prefix:
|
|
|
+ if (eol) {
|
|
|
+ state = ps_start;
|
|
|
+ } else if (*match_ptr && c == *match_ptr) {
|
|
|
+ match_ptr++;
|
|
|
+ } else if (!*match_ptr && c == '=') {
|
|
|
+ p = rev_str;
|
|
|
+ state = ps_string;
|
|
|
+ } else {
|
|
|
+ state = ps_skipline;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case ps_string:
|
|
|
+ if (eol) {
|
|
|
+ *p = '\0';
|
|
|
+ if (!memcmp(rev_str, rev_valid, sizeof rev_valid - 1)) {
|
|
|
+ /* Otherwise input truncated or invalid */
|
|
|
+ printf("[HTTP] setting board revision: %s\n", rev_str);
|
|
|
+ if (!board_info_set(rev_str)) {
|
|
|
+ setenv_cond("status.max80.hw.ver",
|
|
|
+ board_info.version_str);
|
|
|
+ err = Z_OK;
|
|
|
+ } else {
|
|
|
+ err = FWUPDATE_ERR_CONFIG_SAVE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ state = ps_start;
|
|
|
+ } else if (p - rev_str >= sizeof board_info.version_str - 1) {
|
|
|
+ state = ps_skipline;
|
|
|
+ } else {
|
|
|
+ *p++ = c;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case ps_skipline:
|
|
|
+ if (eol)
|
|
|
+ state = ps_start;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } while (c != EOF);
|
|
|
+
|
|
|
+ fclose(f);
|
|
|
+ free(rev_str);
|
|
|
+
|
|
|
+ return httpd_update_done(req, "board revision", err);
|
|
|
+}
|
|
|
+
|
|
|
#define MIN_STATUS_REF 1 /* Minimum refresh time in s */
|
|
|
|
|
|
static void httpd_get_status_extra(FILE *f, httpd_req_t *req)
|
|
@@ -444,9 +556,9 @@ static esp_err_t httpd_lang_redirect(httpd_req_t *req)
|
|
|
return httpd_send_plain(req, 302, lang_buf, len, 0, 0);
|
|
|
}
|
|
|
|
|
|
-#define STRING_MATCHES(str, len, what) \
|
|
|
+#define STRING_MATCHES(str, len, what) \
|
|
|
(((len) == sizeof(what)-1) && !memcmp((str), (what), sizeof(what)-1))
|
|
|
-#define STRING_MATCHES_PREFIX(str, len, what) \
|
|
|
+#define STRING_MATCHES_PREFIX(str, len, what) \
|
|
|
(((len) >= sizeof(what)-1) && !memcmp((str), (what), sizeof(what)-1))
|
|
|
|
|
|
static esp_err_t httpd_sys_handler(httpd_req_t *req)
|
|
@@ -477,7 +589,7 @@ static esp_err_t httpd_sys_handler(httpd_req_t *req)
|
|
|
if (STRING_MATCHES(file, filelen, "getconfig"))
|
|
|
return httpd_get_config_status(req, false);
|
|
|
|
|
|
- if (req->method == HTTP_POST && STRING_MATCHES(file, filelen, "fwupdate"))
|
|
|
+ if (STRING_MATCHES(file, filelen, "fwupdate"))
|
|
|
return httpd_firmware_update(req);
|
|
|
|
|
|
if (STRING_MATCHES(file, filelen, "setconfig"))
|
|
@@ -489,6 +601,9 @@ static esp_err_t httpd_sys_handler(httpd_req_t *req)
|
|
|
if (STRING_MATCHES(file, filelen, "setlang"))
|
|
|
return httpd_set_lang(req, query);
|
|
|
|
|
|
+ if (STRING_MATCHES(file, filelen, "setboardrev"))
|
|
|
+ return httpd_set_board_rev(req);
|
|
|
+
|
|
|
return httpd_err_enoent(req);
|
|
|
}
|
|
|
|
|
@@ -868,7 +983,7 @@ void my_httpd_start(void)
|
|
|
config.uri_match_fn = httpd_uri_match_prefix;
|
|
|
|
|
|
if (httpd_start(&server, &config) != ESP_OK)
|
|
|
- return;
|
|
|
+ return;
|
|
|
|
|
|
esp_register_shutdown_handler(my_httpd_stop);
|
|
|
|