The most important change is local redirects being disabled by default. There is an option called cgi.local-redir that allows enabling this optimization manually back if needed. Local redirects were initially introduced in 1.4.40 but caused many problems for *some* web services. One of problems is breaking Post/Redirect/Get design pattern. With redirects handled on server side there is no browser redirection making it "lose" the POST data. Another possible issue are HTML forms with action="". With CGI local redirects browser may be sending form data to the wrong URL (the one that was supposed to redirect the browser). Signed-off-by: Rafał Miłecki <rafal@milecki.pl>lilik-openwrt-22.03
@ -0,0 +1,62 @@ | |||
From dde50f1939e22926d17342b5d812e9a3034e7e98 Mon Sep 17 00:00:00 2001 | |||
From: Glenn Strauss <gstrauss@gluelogic.com> | |||
Date: Wed, 25 Jan 2017 11:22:39 -0500 | |||
Subject: [PATCH] [mod_cgi] RFC3875 CGI local-redir strict adherence (#2108) | |||
RFC3875 CGI local-redir stricter adherence | |||
do not apply local-redir if any response headers besides "Location" | |||
do not apply local-redir if any response body has been received | |||
(though it might not have been received yet, and we do not wait to find | |||
out, if lighttpd is configured to stream response body back to client) | |||
x-ref: | |||
RFC3875 CGI 1.1 specification section 6.2.2 Local Redirect Response | |||
http://www.ietf.org/rfc/rfc3875 | |||
"CGI local redirect not implemented correctly" | |||
https://redmine.lighttpd.net/issues/2108 | |||
--- | |||
src/mod_cgi.c | 25 ++++++++++++++++++++++++- | |||
1 file changed, 24 insertions(+), 1 deletion(-) | |||
--- a/src/mod_cgi.c | |||
+++ b/src/mod_cgi.c | |||
@@ -527,6 +527,27 @@ static int cgi_demux_response(server *sr | |||
/* parse the response header */ | |||
cgi_response_parse(srv, con, p, hctx->response_header); | |||
+ /* [RFC3875] 6.2.2 Local Redirect Response | |||
+ * | |||
+ * The CGI script can return a URI path and query-string | |||
+ * ('local-pathquery') for a local resource in a Location header field. | |||
+ * This indicates to the server that it should reprocess the request | |||
+ * using the path specified. | |||
+ * | |||
+ * local-redir-response = local-Location NL | |||
+ * | |||
+ * The script MUST NOT return any other header fields or a message-body, | |||
+ * and the server MUST generate the response that it would have produced | |||
+ * in response to a request containing the URL | |||
+ * | |||
+ * scheme "://" server-name ":" server-port local-pathquery | |||
+ * | |||
+ * (Might not have begun to receive body yet, but do skip local-redir | |||
+ * if we already have started receiving a response body (blen > 0)) | |||
+ * (Also, while not required by the RFC, do not send local-redir back | |||
+ * to same URL, since CGI should have handled it internally if it | |||
+ * really wanted to do that internally) | |||
+ */ | |||
if (con->http_status >= 300 && con->http_status < 400) { | |||
/*(con->parsed_response & HTTP_LOCATION)*/ | |||
size_t ulen = buffer_string_length(con->uri.path); | |||
@@ -535,7 +556,9 @@ static int cgi_demux_response(server *sr | |||
&& ds->value->ptr[0] == '/' | |||
&& (0 != strncmp(ds->value->ptr, con->uri.path->ptr, ulen) | |||
|| (ds->value->ptr[ulen] != '\0' && ds->value->ptr[ulen] != '/' && ds->value->ptr[ulen] != '?')) | |||
- && NULL == array_get_element(con->response.headers, "Set-Cookie")) { | |||
+ && 0 == blen | |||
+ && !(con->parsed_response & HTTP_STATUS) /* no "Status" or NPH response line */ | |||
+ && 1 == con->response.headers->used) { | |||
if (++con->loops_per_request > 5) { | |||
log_error_write(srv, __FILE__, __LINE__, "sb", "too many internal loops while processing request:", con->request.orig_uri); | |||
con->http_status = 500; /* Internal Server Error */ |
@ -0,0 +1,46 @@ | |||
From 51ff7ac504f7001dc54807f9b2a72de891ab9ee5 Mon Sep 17 00:00:00 2001 | |||
From: Glenn Strauss <gstrauss@gluelogic.com> | |||
Date: Wed, 22 Feb 2017 11:58:21 -0500 | |||
Subject: [PATCH] [mod_cgi] status 200 OK if no hdrs (deprecated) (#2786) | |||
set status 200 OK if CGI does not return CGI headers | |||
Note: | |||
This mode in lighttpd is deprecated and may be removed in the next major | |||
release of lighttpd. CGI scripts should return a proper CGI header in | |||
the response, even if that header is empty and followed by a blank line, | |||
before return response body. | |||
Without a proper CGI response header, the first line(s) of the response | |||
might be incorrectly construed as being CGI response headers, especially | |||
if they contain ':', and response may be corrupted. That is why this | |||
mode is deprecated (and not supported in numerous other web servers). | |||
The minimal valid CGI response header is "\n", which lighttpd will treat | |||
as equivalent to "Status: 200\n\n" | |||
x-ref: | |||
"error 500 (mod_cgi.c.601) cgi died" | |||
https://redmine.lighttpd.net/issues/2786 | |||
--- | |||
src/mod_cgi.c | 2 ++ | |||
1 file changed, 2 insertions(+) | |||
--- a/src/mod_cgi.c | |||
+++ b/src/mod_cgi.c | |||
@@ -502,6 +502,7 @@ static int cgi_demux_response(server *sr | |||
if (0 != http_chunk_append_buffer(srv, con, hctx->response_header)) { | |||
return FDEVENT_HANDLED_ERROR; | |||
} | |||
+ if (0 == con->http_status) con->http_status = 200; /* OK */ | |||
} else { | |||
const char *bstart; | |||
size_t blen; | |||
@@ -846,6 +847,7 @@ static handler_t cgi_handle_fdevent(serv | |||
cgi_connection_close(srv, hctx); | |||
return HANDLER_ERROR; | |||
} | |||
+ if (0 == con->http_status) con->http_status = 200; /* OK */ | |||
} else { | |||
# if 0 | |||
log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents); |
@ -0,0 +1,105 @@ | |||
From 57ab20ace504fdb6e0944ef6fa6e0ce35adc4446 Mon Sep 17 00:00:00 2001 | |||
From: Glenn Strauss <gstrauss@gluelogic.com> | |||
Date: Sun, 26 Feb 2017 17:49:47 -0500 | |||
Subject: [PATCH] [mod_cgi] cgi.local-redir = [enable|disable] (#2108, #2793) | |||
new directive cgi.local-redir = [enable|disable] | |||
*disable* RFC3875 6.2.2 local-redir by default. | |||
(behavior change from when local-redir support added in lighttpd 1.4.40) | |||
The reason for this behavior change is that CGI local-redir support | |||
(RFC3875 6.2.2) is an optimization. Absence of support may result in | |||
additional latency in servicing a request due the additional round-trip | |||
to the client, but that was the prior behavior (before lighttpd 1.4.40) | |||
and is the behavior of web servers which do not support CGI local-redir. | |||
However, enabling CGI local-redir by default may result in broken links | |||
in the case where a user config (unaware of CGI local-redir behavior) | |||
returns HTML pages containing *relative* paths (not root-relative paths) | |||
which are relative to the location of the local-redir target document, | |||
and the local-redir target document is located at a different URL-path | |||
from the original CGI request. | |||
x-ref: | |||
RFC3875 CGI 1.1 specification section 6.2.2 Local Redirect Response | |||
http://www.ietf.org/rfc/rfc3875 | |||
"CGI local redirect not implemented correctly" | |||
https://redmine.lighttpd.net/issues/2108 | |||
"1.4.40 regression: broken redirect (using Location) between url.rewrite-once URLs" | |||
https://redmine.lighttpd.net/issues/2793 | |||
--- | |||
src/mod_cgi.c | 9 ++++++++- | |||
tests/lighttpd.conf | 1 + | |||
2 files changed, 9 insertions(+), 1 deletion(-) | |||
--- a/src/mod_cgi.c | |||
+++ b/src/mod_cgi.c | |||
@@ -66,6 +66,7 @@ typedef struct { | |||
typedef struct { | |||
array *cgi; | |||
unsigned short execute_x_only; | |||
+ unsigned short local_redir; | |||
unsigned short xsendfile_allow; | |||
array *xsendfile_docroot; | |||
} plugin_config; | |||
@@ -172,6 +173,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_default | |||
{ "cgi.execute-x-only", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ | |||
{ "cgi.x-sendfile", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ | |||
{ "cgi.x-sendfile-docroot", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ | |||
+ { "cgi.local-redir", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */ | |||
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET} | |||
}; | |||
@@ -189,6 +191,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_default | |||
s->cgi = array_init(); | |||
s->execute_x_only = 0; | |||
+ s->local_redir = 0; | |||
s->xsendfile_allow= 0; | |||
s->xsendfile_docroot = array_init(); | |||
@@ -196,6 +199,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_default | |||
cv[1].destination = &(s->execute_x_only); | |||
cv[2].destination = &(s->xsendfile_allow); | |||
cv[3].destination = s->xsendfile_docroot; | |||
+ cv[4].destination = &(s->local_redir); | |||
p->config_storage[i] = s; | |||
@@ -549,7 +553,7 @@ static int cgi_demux_response(server *sr | |||
* to same URL, since CGI should have handled it internally if it | |||
* really wanted to do that internally) | |||
*/ | |||
- if (con->http_status >= 300 && con->http_status < 400) { | |||
+ if (hctx->conf.local_redir && con->http_status >= 300 && con->http_status < 400) { | |||
/*(con->parsed_response & HTTP_LOCATION)*/ | |||
size_t ulen = buffer_string_length(con->uri.path); | |||
data_string *ds; | |||
@@ -1321,6 +1325,7 @@ static int mod_cgi_patch_connection(serv | |||
PATCH(cgi); | |||
PATCH(execute_x_only); | |||
+ PATCH(local_redir); | |||
PATCH(xsendfile_allow); | |||
PATCH(xsendfile_docroot); | |||
@@ -1340,6 +1345,8 @@ static int mod_cgi_patch_connection(serv | |||
PATCH(cgi); | |||
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.execute-x-only"))) { | |||
PATCH(execute_x_only); | |||
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.local-redir"))) { | |||
+ PATCH(local_redir); | |||
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.x-sendfile"))) { | |||
PATCH(xsendfile_allow); | |||
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.x-sendfile-docroot"))) { | |||
--- a/tests/lighttpd.conf | |||
+++ b/tests/lighttpd.conf | |||
@@ -110,6 +110,7 @@ fastcgi.server = ( | |||
) ), | |||
) | |||
+cgi.local-redir = "enable" | |||
cgi.assign = ( | |||
".pl" => env.PERL, | |||
".cgi" => env.PERL, |