|
@@ -144,7 +144,8 @@ static const char text_plain[] = "text/plain; charset=\"UTF-8\"";
|
|
|
enum hsp_flags {
|
|
|
HSP_CLOSE = 1,
|
|
|
HSP_CRLF = 2,
|
|
|
- HSP_CLOSE_SOCKET = 4
|
|
|
+ HSP_CLOSE_SOCKET = 4,
|
|
|
+ HSP_REFERER = 8 /* Use referer as body (for redirects) */
|
|
|
};
|
|
|
|
|
|
static void httpd_print_request(const httpd_req_t *req)
|
|
@@ -152,6 +153,22 @@ static void httpd_print_request(const httpd_req_t *req)
|
|
|
printf("[HTTP] %s %s\n", http_method_str(req->method), req->uri);
|
|
|
}
|
|
|
|
|
|
+static char *httpd_req_get_hdr(httpd_req_t *req, const char *field, size_t *lenp)
|
|
|
+{
|
|
|
+ size_t len = httpd_req_get_hdr_value_len(req, field);
|
|
|
+ char *val = NULL;
|
|
|
+ if (len) {
|
|
|
+ val = malloc(len+1);
|
|
|
+ if (val) {
|
|
|
+ httpd_req_get_hdr_value_str(req, field, val, len+1);
|
|
|
+ val[len] = '\0';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (lenp)
|
|
|
+ *lenp = len;
|
|
|
+ return val;
|
|
|
+}
|
|
|
+
|
|
|
static esp_err_t httpd_send_plain(httpd_req_t *req,
|
|
|
unsigned int rcode,
|
|
|
const char *body, size_t blen,
|
|
@@ -170,30 +187,33 @@ 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;
|
|
|
|
|
|
- char *refresher = (char *)"";
|
|
|
- if (refresh) {
|
|
|
- size_t referer_length = httpd_req_get_hdr_value_len(req, "Referer");
|
|
|
- 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);
|
|
|
+ char *referer = NULL;
|
|
|
+ char *refresher_buf = NULL;
|
|
|
+
|
|
|
+ if (refresh || (flags & HSP_REFERER)) {
|
|
|
+ size_t referer_len;
|
|
|
+ referer = httpd_req_get_hdr(req, "Referer", &referer_len);
|
|
|
+
|
|
|
+ /* "Effective" referer */
|
|
|
+ const char * const ereferer = referer ? referer : "/";
|
|
|
+
|
|
|
+ if (refresh) {
|
|
|
+ asprintf(&refresher_buf, "Refresh: %u;url=%s\r\n",
|
|
|
+ refresh, ereferer);
|
|
|
+ }
|
|
|
+ if (flags & HSP_REFERER) {
|
|
|
+ body = ereferer;
|
|
|
+ blen = referer ? referer_len : 1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ const char * const refresher = refresher_buf ? refresher_buf : "";
|
|
|
+
|
|
|
if (redirect) {
|
|
|
- size_t blenadj = sizeof("3xx Redirect \r"); /* \0 -> \n so don't include it */
|
|
|
+ /* \0 -> \n so don't include it */
|
|
|
+ size_t blenadj = sizeof("3xx Redirect \r");
|
|
|
+
|
|
|
+ /* Always CR LF */
|
|
|
flags |= HSP_CRLF;
|
|
|
|
|
|
/* Drop any CR LF already in the redirect string */
|
|
@@ -230,8 +250,11 @@ static esp_err_t httpd_send_plain(httpd_req_t *req,
|
|
|
closer, refresher);
|
|
|
}
|
|
|
|
|
|
- if (*refresher)
|
|
|
- free(refresher);
|
|
|
+ if (refresher_buf)
|
|
|
+ free(refresher_buf);
|
|
|
+
|
|
|
+ if (referer)
|
|
|
+ free(referer);
|
|
|
|
|
|
if (!header)
|
|
|
return ESP_ERR_NO_MEM;
|
|
@@ -354,7 +377,12 @@ static esp_err_t httpd_set_lang(httpd_req_t *req, const char *query)
|
|
|
read_config(NULL, true); /* Save configuration */
|
|
|
}
|
|
|
|
|
|
- return httpd_send_plain(req, 200, SL("Language set"), HSP_CRLF, 1);
|
|
|
+ /*
|
|
|
+ * 303 = "See other": proper return code saying "this is not what
|
|
|
+ * you asked for, this is *about* what you asked for"; see spec
|
|
|
+ * but this is exactly what we want here.
|
|
|
+ */
|
|
|
+ return httpd_send_plain(req, 303, NULL, 0, HSP_REFERER, 0);
|
|
|
}
|
|
|
|
|
|
static esp_err_t httpd_get_lang(httpd_req_t *req)
|