Browse Source

httpd: unify sys URL handlers; language redirect

H. Peter Anvin 2 years ago
parent
commit
af2834620d
4 changed files with 86 additions and 52 deletions
  1. 86 52
      esp32/max80/httpd.c
  2. BIN
      esp32/output/max80.ino.bin
  3. BIN
      fpga/output/v1.fw
  4. BIN
      fpga/output/v2.fw

+ 86 - 52
esp32/max80/httpd.c

@@ -9,6 +9,9 @@
 #include <unzipLIB.h>
 
 static httpd_handle_t httpd;
+static const char fallback_language[] = "en"; /* For unknown language */
+static const char index_filename[] = "index.html"; /* For a directory "file" */
+#define MAX_LANG_LEN 16
 
 /* Looping version of httpd_send(); this is a hidden function in the server */
 static esp_err_t httpd_send_all(httpd_req_t *req, const void *buf, size_t len)
@@ -163,11 +166,21 @@ static esp_err_t httpd_send_plain(httpd_req_t *req,
     const char *closer = flags & HSP_CLOSE ? "Connection: close\r\n" : "";
     bool redirect = rcode >= 300 && rcode <= 399;
 
-    static const char refresher[] = "Refresh: %u;url=/";
-    char refresh_str[sizeof(refresher)-2 + sizeof(unsigned int)*3];
-    refresh_str[0] = '\0';
-    if (refresh)
-	snprintf(refresh_str, sizeof refresh_str, refresher, refresh);
+    char *refresher = NULL;
+    if (refresh) {
+	size_t referer_length = httpd_req_get_hdr_value_len(req, "Referer");
+	if (referer_length) {
+	    size_t refbufsize = sizeof("Refresh: ;url=\r\n")
+		+ 3*sizeof(unsigned int) + referer_length;
+	    refresher = malloc(refbufsize);
+	    size_t rlen = snprintf(refresher, refbufsize, "Refresh: %u;url=", refresh);
+	    httpd_req_get_hdr_value_str(req, "Referer", refresher+rlen,
+					refbufsize-rlen);
+	    memcpy(refresher+rlen+referer_length, "\r\n", 3);
+	}
+    }
+    if (!refresher)
+	refresher = (char *)"";
 
     if (redirect) {
 	size_t blenadj = sizeof("3xx Redirect \r"); /* \0 -> \n so don't include it */
@@ -183,7 +196,7 @@ static esp_err_t httpd_send_plain(httpd_req_t *req,
 			"\r\n"
 			"%3u Redirect ",
 			rcode, text_plain, blen + blenadj,
-			now, (int)blen, body, closer, refresh_str, rcode);
+			now, (int)blen, body, closer, refresher, rcode);
     } else {
 	size_t blenadj = (flags & HSP_CRLF) ? 2 : 0;
 
@@ -196,9 +209,12 @@ static esp_err_t httpd_send_plain(httpd_req_t *req,
 			"%s%s"
 			"\r\n",
 			rcode, text_plain, blen + blenadj, now,
-			closer, refresh_str);
+			closer, refresher);
     }
 
+    if (!*refresher)
+	free(refresher);
+
     if (!header)
 	return ESP_ERR_NO_MEM;
 
@@ -217,7 +233,8 @@ static esp_err_t httpd_send_plain(httpd_req_t *req,
     return err ? err : (flags & HSP_CLOSE_SOCKET) ? ESP_FAIL : ESP_OK;
 }
 
-#define HTTP_ERR(r,e,s) httpd_send_plain((r), (e), s, sizeof(s)-1, HSP_CRLF, 0)
+#define SL(s) (s), (sizeof(s)-1)
+#define HTTP_ERR(r,e,s) httpd_send_plain((r), (e), SL(s), HSP_CRLF, 0)
 
 static esp_err_t httpd_err_enoent(httpd_req_t *req)
 {
@@ -297,67 +314,86 @@ static esp_err_t httpd_set_config(httpd_req_t *req, const char *query)
     return httpd_update_done(req, "Configuration", rv1 ? rv1 : rv2);
 }
 
+static esp_err_t httpd_get_config(httpd_req_t *req)
+{
+    FILE *f = httpd_fopen_write(req);
+    if (!f)
+	return HTTP_ERR(req, 500, "Unable to get request handle");
+
+    httpd_resp_set_type(req, text_plain);
+    httpd_resp_set_hdr(req, "Cache-Control", "no-cache");
+
+    int rv = write_config(f);
+    fclose(f);
+    return rv ? ESP_FAIL : ESP_OK;
+}
+
 static esp_err_t httpd_set_lang(httpd_req_t *req, const char *query)
 {
-    if (query && *query) {
-	setenv_config("LANG", query);
+    if (query) {
+	int qlen = strlen(query);
+	setenv_config("LANG", qlen && qlen <= MAX_LANG_LEN ? query : NULL);
 	read_config(NULL, true);	/* Save configuration */
     }
 
-    return httpd_send_plain(req, 302, "/", 1, 0, 0);
+    return httpd_send_plain(req, 200, SL("Language set"), HSP_CRLF, 1);
+}
+
+static esp_err_t httpd_get_lang(httpd_req_t *req)
+{
+    const char *lang = getenv_def("LANG", "");
+
+    return httpd_send_plain(req, 200, lang, strlen(lang), HSP_CRLF, 0);
+}
+
+static esp_err_t httpd_lang_redirect(httpd_req_t *req)
+{
+    char lang_buf[sizeof("/lang/") + MAX_LANG_LEN];
+    int len = snprintf(lang_buf, sizeof lang_buf, "/lang/%s",
+		       getenv_def("LANG", fallback_language));
+
+    return httpd_send_plain(req, 302, lang_buf, len, 0, 0);
 }
 
 #define STRING_MATCHES(str, len, what) \
     (((len) == sizeof(what)-1) && !memcmp((str), (what), sizeof(what)-1))
 
-static esp_err_t httpd_sys_post_handler(httpd_req_t *req)
+static esp_err_t httpd_sys_handler(httpd_req_t *req)
 {
     httpd_print_request(req);
 
-    if (!httpd_req_get_hdr_value_len(req, "Content-Length"))
+    if (req->method == HTTP_POST &&
+	!httpd_req_get_hdr_value_len(req, "Content-Length")) {
 	return HTTP_ERR(req, 411, "Length required");
+    }
 
-    if (strncmp(req->uri, "/sys/", 5))
+    const char *query = strchrnul(req->uri, '?');
+
+    if (query < req->uri+5 || memcmp(req->uri, "/sys/", 5))
 	return httpd_err_enoent(req); /* This should never happen */
 
     const char *file = req->uri + 5;
-    size_t filelen = strcspn(file, "?");
-    const char *query = NULL;
-    if (file[filelen] == '?')
-	query = &file[filelen] + 1;
+    size_t filelen = query - file;
 
-    if (STRING_MATCHES(file, filelen, "fwupdate"))
-	return httpd_firmware_update(req);
-
-    if (STRING_MATCHES(file, filelen, "setconfig"))
-	return httpd_set_config(req, query);
+    query = *query == '?' ? query+1 : NULL;
 
     if (STRING_MATCHES(file, filelen, "lang"))
-	return httpd_set_lang(req, query);
-
-    return httpd_err_enoent(req);
-}
+	return httpd_lang_redirect(req);
 
-static esp_err_t httpd_get_config(httpd_req_t *req)
-{
-    FILE *f = httpd_fopen_write(req);
-    if (!f)
-	return HTTP_ERR(req, 500, "Unable to get request handle");
+    if (STRING_MATCHES(file, filelen, "getconfig"))
+	return httpd_get_config(req);
 
-    httpd_resp_set_type(req, text_plain);
-    httpd_resp_set_hdr(req, "Cache-Control", "no-store");
+    if (req->method == HTTP_POST && STRING_MATCHES(file, filelen, "fwupdate"))
+	return httpd_firmware_update(req);
 
-    int rv = write_config(f);
-    fclose(f);
-    return rv ? ESP_FAIL : ESP_OK;
-}
+    if (STRING_MATCHES(file, filelen, "setconfig"))
+	return httpd_set_config(req, query);
 
-static esp_err_t httpd_sys_get_handler(httpd_req_t *req)
-{
-    httpd_print_request(req);
+    if (STRING_MATCHES(file, filelen, "getlang"))
+	return httpd_get_lang(req);
 
-    if (!strcmp(req->uri, "/sys/getconfig"))
-	return httpd_get_config(req);
+    if (STRING_MATCHES(file, filelen, "setlang"))
+	return httpd_set_lang(req, query);
 
     return httpd_err_enoent(req);
 }
@@ -398,8 +434,6 @@ static const struct mime_type mime_types[] = {
 
 static esp_err_t httpd_static_handler(httpd_req_t *req)
 {
-    static const char index_filename[] = "index.html";
-    static const char fallback_lang[] = "en";
     size_t buffer_size = UNZ_BUFSIZE;
     const char *uri, *enduri;
     bool add_index;
@@ -438,8 +472,8 @@ static esp_err_t httpd_static_handler(httpd_req_t *req)
 
     const char *lang = getenv_def("LANG", "");
     const size_t lang_size = lang ? strlen(lang)+1 : 0;
-    const size_t lang_space = (lang_size < sizeof fallback_lang
-			       ? sizeof fallback_lang : lang_size) + 1;
+    const size_t lang_space = (lang_size < sizeof fallback_language
+			       ? sizeof fallback_language : lang_size) + 1;
     const size_t filename_buffer_size =
 	(enduri - uri) + lang_space + 2 + sizeof index_filename;
 
@@ -489,8 +523,8 @@ static esp_err_t httpd_static_handler(httpd_req_t *req)
 	    }
 	    break;
 	case 2:
-	    filename = filebase - sizeof fallback_lang;
-	    memcpy(filename, fallback_lang, sizeof fallback_lang - 1);
+	    filename = filebase - sizeof fallback_language;
+	    memcpy(filename, fallback_language, sizeof fallback_language - 1);
 	    break;
 	default:
 	    filename = filebase;
@@ -593,7 +627,7 @@ static esp_err_t httpd_static_handler(httpd_req_t *req)
     }
 
     if (unzOpenCurrentFile(unz) != UNZ_OK) {
-	err = httpd_resp_send_err(req, 500, "Cannot open file in archive");
+	err = HTTP_ERR(req, 500, "Cannot open file in archive");
 	goto out;
     }
     file_open = true;
@@ -670,7 +704,7 @@ static const httpd_uri_t uri_handlers[] = {
     {
 	.uri      = "sys",
 	.method   = HTTP_GET,
-	.handler  = httpd_sys_get_handler,
+	.handler  = httpd_sys_handler,
 	.user_ctx = NULL
     },
     {
@@ -688,7 +722,7 @@ static const httpd_uri_t uri_handlers[] = {
     {
 	.uri      = "sys",
 	.method   = HTTP_POST,
-	.handler  = httpd_sys_post_handler,
+	.handler  = httpd_sys_handler,
 	.user_ctx = NULL
     },
 };

BIN
esp32/output/max80.ino.bin


BIN
fpga/output/v1.fw


BIN
fpga/output/v2.fw