Bläddra i källkod

httpd: allow static redirect; remove index.html and lang prefix

Remove index.html, and remove the lang prefix hacks. Instead allow a
filename to end with _redir to do an http 302 redirect.
H. Peter Anvin 2 år sedan
förälder
incheckning
cc21d3a2ea
8 ändrade filer med 93 tillägg och 58 borttagningar
  1. 90 55
      esp32/max80/httpd.c
  2. BIN
      esp32/output/max80.ino.bin
  3. 1 0
      esp32/www/_redir
  4. 1 1
      esp32/www/head.html
  5. 0 1
      esp32/www/index.html
  6. 1 1
      esp32/www/status.html
  7. BIN
      fpga/output/v1.fw
  8. BIN
      fpga/output/v2.fw

+ 90 - 55
esp32/max80/httpd.c

@@ -10,7 +10,7 @@
 
 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" */
+static const char redir_filename[] = "_redir"; /* For a directory "file" */
 #define MAX_LANG_LEN 16
 
 /* Looping version of httpd_send(); this is a hidden function in the server */
@@ -160,32 +160,48 @@ static esp_err_t httpd_send_plain(httpd_req_t *req,
     int hlen;
     const char *now = http_now();
 
+    MSG("http_send_plain %u \"%.*s\"\n", rcode, (int)blen, body);
+    
     if (rcode > 499)
 	flags |= HSP_CLOSE;
 
     const char *closer = flags & HSP_CLOSE ? "Connection: close\r\n" : "";
     bool redirect = rcode >= 300 && rcode <= 399;
 
-    char *refresher = NULL;
+    char *refresher = (char *)"";
     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);
+	const size_t refhdrsize = sizeof("Refresh: ;url=") +
+	    3*sizeof(unsigned int);
+	refresher = malloc(refhdrsize + referer_length + 4);
+	if (!refresher) {
+	    refresher = (char *)"";
+	} else {
+	    size_t rlen = snprintf(refresher, refhdrsize,
+				   "Refresh: %u;url=", refresh);
+	    if (referer_length) {
+		httpd_req_get_hdr_value_str(req, "Referer", refresher+rlen,
+					    referer_length+1);
+		rlen += referer_length;
+	    } else {
+		refresher[rlen++] = '/';
+	    }
+	    memcpy(refresher+rlen, "\r\n", 3);
 	}
     }
-    if (!refresher)
-	refresher = (char *)"";
 
     if (redirect) {
 	size_t blenadj = sizeof("3xx Redirect \r"); /* \0 -> \n so don't include it */
 	flags |= HSP_CRLF;
 
+	/* Drop any CR LF already in the redirect string */
+	for (size_t bchk = 0; bchk < blen; bchk++) {
+	    if (body[bchk] == '\r' || body[bchk] == '\n') {
+		blen = bchk;
+		break;
+	    }
+	}
+
 	hlen = asprintf(&header,
 			"HTTP/1.1 %u\r\n"
 			"Content-Type: %s\r\n"
@@ -204,7 +220,7 @@ static esp_err_t httpd_send_plain(httpd_req_t *req,
 			"HTTP/1.1 %u\r\n"
 			"Content-Type: %s\r\n"
 			"Content-Length: %zu\r\n"
-			"Cache-Control: no-store\r\n"
+			"Cache-Control: no-cache\r\n"
 			"Date: %s\r\n"
 			"%s%s"
 			"\r\n",
@@ -408,6 +424,7 @@ struct mime_type {
 };
 
 #define MT_CHARSET	1	/* Add charset to Content-Type */
+#define MT_REDIR	2	/* It is a redirect */
 
 static const struct mime_type mime_types[] = {
     { ".html",  5, MT_CHARSET, "text/html"                 },
@@ -429,6 +446,7 @@ static const struct mime_type mime_types[] = {
     { ".xml",   4, MT_CHARSET, "text/xml"                  },
     { ".bin",   4, 0,          "application/octet-stream"  },
     { ".fw",    3, 0,          "application/octet-stream"  },
+    { "_redir", 6, MT_REDIR,   NULL                        },
     { NULL,     0, MT_CHARSET, "text/plain"                }  /* default */
 };
 
@@ -436,7 +454,7 @@ static esp_err_t httpd_static_handler(httpd_req_t *req)
 {
     size_t buffer_size = UNZ_BUFSIZE;
     const char *uri, *enduri;
-    bool add_index;
+    bool is_dir;
     char *buffer = NULL;
     ZIPFILE *zip = NULL;
     unzFile unz  = NULL;
@@ -460,22 +478,18 @@ static esp_err_t httpd_static_handler(httpd_req_t *req)
 	}
     }
     if (enduri == uri) {
-	add_index = true;
+	is_dir = true;
     } else if (last_slash == enduri-1) {
-	add_index = true;
+	is_dir = true;
 	enduri--;		/* Drop terminal slash */
 	if (first_slash == last_slash)
 	    first_slash = NULL;
     } else {
-	add_index = false;	/* Try the plain filename first */
+	is_dir = false;	/* Try the plain filename first */
     }
 
-    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_language
-			       ? sizeof fallback_language : lang_size) + 1;
     const size_t filename_buffer_size =
-	(enduri - uri) + lang_space + 2 + sizeof index_filename;
+	(enduri - uri) + 2 + sizeof redir_filename;
 
     if (buffer_size < filename_buffer_size)
 	buffer_size = filename_buffer_size;
@@ -487,7 +501,7 @@ static esp_err_t httpd_static_handler(httpd_req_t *req)
 	goto out;
     }
 
-    char * const filebase = buffer + lang_space;
+    char * const filebase = buffer + 1;
     char * const endbase  = mempcpy(filebase, uri, enduri - uri);
     filebase[-1] = '/';
 
@@ -499,76 +513,97 @@ static esp_err_t httpd_static_handler(httpd_req_t *req)
 	goto out;
     }
 
-    char *filename, *endfile;
+    char * const filename = filebase; /* Separate for future needs */
+    char *endfile = endbase;
 
     unsigned int m;
     bool found = false;
-    for (m = add_index; m < 6; m += (add_index+1)) {
-	if (m & 1) {
-	    char *sx = endbase - (endbase[-1] == '/');
-	    *sx++ = '/';
-	    endfile = mempcpy(sx, index_filename, sizeof index_filename) - 1;
-	} else {
+    for (m = is_dir ? 2 : 0; m < 3; m++) {
+	char *sx;
+	switch (m) {
+	default:		/* filename = /url */
 	    endfile = endbase;
-	}
-	*endfile = '\0';
-
-	switch (m >> 1) {
-	case 1:
-	    if (!lang) {
-		filename = NULL;
-	    } else {
-		filename = filebase - lang_size;
-		memcpy(filename, lang, lang_size-1);
-	    }
 	    break;
-	case 2:
-	    filename = filebase - sizeof fallback_language;
-	    memcpy(filename, fallback_language, sizeof fallback_language - 1);
+	case 1:			/* filename = /url_redir */
+	    sx = endbase;
+	    endfile = mempcpy(sx, redir_filename, sizeof redir_filename) - 1;
 	    break;
-	default:
-	    filename = filebase;
+	case 2:			/* filename = /url/_redir */
+	    sx = endbase - (endbase[-1] == '/');
+	    *sx++ = '/';
+	    endfile = mempcpy(sx, redir_filename, sizeof redir_filename) - 1;
 	    break;
 	}
+	*endfile = '\0';
 
 	if (!filename)
 	    continue;
 
 	filename[-1] = '/';
-	MSG("trying to open: %s\n", filename);
+	MSG("trying to open: %s... ", filename);
 	if (unzLocateFile(unz, filename, 1) == UNZ_OK) {
+	    CMSG("found\n");
 	    found = true;
 	    break;
+	} else {
+	    CMSG("not found\n");
 	}
     }
 
-    size_t filelen = endfile - filename;
-
     if (!found) {
 	err = httpd_err_enoent(req);
 	goto out;
-    } else if (m) {
-	err = httpd_send_plain(req, 302 - (m == 1), filename-1, filelen+1, 0, 0);
-	goto out;
     }
 
-    /* Note: p points to the end of the filename string */
+    size_t filelen = endfile - filename;
 
     const struct mime_type *mime_type = mime_types;
     /* The default entry with length 0 will always match */
     while (mime_type->ext_len) {
 	len = mime_type->ext_len;
 
-	if (len < filelen && !memcmp(endfile - len, mime_type->ext, len))
+	if (len <= filelen && !memcmp(endfile - len, mime_type->ext, len))
 	    break;
 
 	mime_type++;
     }
 
+    MSG("found %s ext %s type %s\n",
+	filename,
+	mime_type->ext ? mime_type->ext : "(none)",
+	mime_type->mime ? mime_type->mime : "(none)");
+    
     unz_file_info fileinfo;
     memset(&fileinfo, 0, sizeof fileinfo);
     unzGetCurrentFileInfo(unz, &fileinfo, NULL, 0, NULL, 0, NULL, 0);
 
+    MSG("len %u compressed %u\n",
+	fileinfo.uncompressed_size,
+	fileinfo.compressed_size);
+
+    /*
+     * Is it a redirect?
+     */
+    if (mime_type->flags & MT_REDIR) {
+	if (fileinfo.uncompressed_size > buffer_size ||
+	    unzOpenCurrentFile(unz) != UNZ_OK) {
+	    err = HTTP_ERR(req, 500, "Cannot open file in archive");
+	    goto out;
+	}
+	file_open = true;
+
+	len = fileinfo.uncompressed_size;
+	if (unzReadCurrentFile(unz, buffer, len) != len) {
+	    err = ESP_ERR_HTTPD_RESULT_TRUNC;
+	    goto out;
+	}
+
+	MSG("redirect: %.*s\n", (int)len, buffer);
+	
+	err = httpd_send_plain(req, 302, buffer, len, 0, 0);
+	goto out;
+    }
+    
     /*
      * Hopefully the combination of date and CRC
      * is strong enough to quality for a "strong" ETag
@@ -627,7 +662,7 @@ static esp_err_t httpd_static_handler(httpd_req_t *req)
     }
 
     if (unzOpenCurrentFile(unz) != UNZ_OK) {
-	err = HTTP_ERR(req, 500, "Cannot open file in archive");
+	err = HTTP_ERR(req, 400, "Cannot open file in archive");
 	goto out;
     }
     file_open = true;

BIN
esp32/output/max80.ino.bin


+ 1 - 0
esp32/www/_redir

@@ -0,0 +1 @@
+/config.html

+ 1 - 1
esp32/www/head.html

@@ -19,7 +19,7 @@
 </div>
 
 <nav class="navbar" role="navigation">
-  <a href="index.html" class="text status">Status</a>
+  <a href="status.html" class="text status">Status</a>
   <a href="config.html" class="text config">Configuration</a>
   <a href="update.html" class="text update">Update</a>
   <span class="pad"></span>

+ 0 - 1
esp32/www/index.html

@@ -1 +0,0 @@
-status.html

+ 1 - 1
esp32/www/status.html

@@ -8,7 +8,7 @@
   <body>
     <script>inc("head.html")</script>
     <script>inc("showstatus.html")</script>
-    <script>loadstatus('sys/getstatus')</script>
+    <script>load('sys/getstatus')</script>
     <script>translate()</script>
   </body>
 </html>

BIN
fpga/output/v1.fw


BIN
fpga/output/v2.fw