server.error-handler new directive for error pages

Merge branch 'feature-2702-server.error-handler' into master
personal/stbuehler/mod-csrf-old
Glenn Strauss 7 years ago
commit a3d4aa9f23

@ -364,6 +364,12 @@ $HTTP["url"] =~ "\.pdf$" {
##
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi", ".scgi" )
##
## error-handler for all status 400-599
##
#server.error-handler = "/error-handler.html"
#server.error-handler = "/error-handler.php"
##
## error-handler for status 404
##

@ -245,6 +245,7 @@ typedef struct {
buffer *document_root;
buffer *server_name;
buffer *error_handler;
buffer *error_handler_404;
buffer *server_tag;
buffer *dirlist_encoding;
buffer *errorfile_prefix;
@ -446,9 +447,8 @@ typedef struct {
buffer *server_name;
/* error-handler */
buffer *error_handler;
int error_handler_saved_status;
int in_error_handler;
http_method_t error_handler_saved_method;
struct server_socket *srv_socket; /* reference to the server-socket */

@ -52,7 +52,7 @@ static int config_insert(server *srv) {
{ "server.max-read-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
{ "server.max-write-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 21 */
{ "server.error-handler-404", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
{ "server.error-handler", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
{ "server.max-fds", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 23 */
#ifdef HAVE_LSTAT
{ "server.follow-symlink", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 24 */
@ -112,6 +112,7 @@ static int config_insert(server *srv) {
{ "server.upload-temp-file-size", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_SERVER }, /* 68 */
{ "mimetype.xattr-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 69 */
{ "server.listen-backlog", NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION }, /* 70 */
{ "server.error-handler-404", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 71 */
{ "server.host",
"use server.bind instead",
@ -193,6 +194,7 @@ static int config_insert(server *srv) {
s->ssl_pemfile = buffer_init();
s->ssl_ca_file = buffer_init();
s->error_handler = buffer_init();
s->error_handler_404 = buffer_init();
s->server_tag = buffer_init();
s->ssl_cipher_list = buffer_init();
s->ssl_dh_file = buffer_init();
@ -288,6 +290,7 @@ static int config_insert(server *srv) {
cv[66].destination = &(s->ssl_honor_cipher_order);
cv[67].destination = &(s->ssl_empty_fragments);
cv[70].destination = &(s->listen_backlog);
cv[71].destination = s->error_handler_404;
srv->config_storage[i] = s;
@ -336,6 +339,7 @@ int config_setup_connection(server *srv, connection *con) {
PATCH(max_write_idle);
PATCH(use_xattr);
PATCH(error_handler);
PATCH(error_handler_404);
PATCH(errorfile_prefix);
#ifdef HAVE_LSTAT
PATCH(follow_symlink);
@ -410,8 +414,10 @@ int config_patch_connection(server *srv, connection *con) {
PATCH(document_root);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
PATCH(range_requests);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.error-handler-404"))) {
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.error-handler"))) {
PATCH(error_handler);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.error-handler-404"))) {
PATCH(error_handler_404);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.errorfile-prefix"))) {
PATCH(errorfile_prefix);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("mimetype.assign"))) {

@ -445,7 +445,6 @@ connection *connection_init(server *srv) {
CLEAN(parse_request);
CLEAN(server_name);
CLEAN(error_handler);
CLEAN(dst_addr_buf);
#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
CLEAN(tlsext_server_name);
@ -516,7 +515,6 @@ void connections_free(server *srv) {
CLEAN(parse_request);
CLEAN(server_name);
CLEAN(error_handler);
CLEAN(dst_addr_buf);
#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
CLEAN(tlsext_server_name);
@ -589,7 +587,6 @@ int connection_reset(server *srv, connection *con) {
CLEAN(parse_request);
CLEAN(server_name);
CLEAN(error_handler);
#if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
CLEAN(tlsext_server_name);
#endif
@ -634,7 +631,9 @@ int connection_reset(server *srv, connection *con) {
/* config_cond_cache_reset(srv, con); */
con->header_len = 0;
con->in_error_handler = 0;
con->error_handler_saved_status = 0;
/*con->error_handler_saved_method = HTTP_METHOD_UNSET;*/
/*(error_handler_saved_method value is not valid unless error_handler_saved_status is set)*/
config_setup_connection(srv, con);
@ -1024,39 +1023,83 @@ int connection_state_machine(server *srv, connection *con) {
switch (r = http_response_prepare(srv, con)) {
case HANDLER_FINISHED:
if (con->error_handler_saved_status > 0) {
con->request.http_method = con->error_handler_saved_method;
}
if (con->mode == DIRECT) {
if (con->http_status == 404 ||
con->http_status == 403) {
/* 404 error-handler */
if (con->error_handler_saved_status) {
if (con->error_handler_saved_status > 0) {
con->http_status = con->error_handler_saved_status;
} else if (con->http_status == 404 || con->http_status == 403) {
/* error-handler-404 is a 404 */
con->http_status = -con->error_handler_saved_status;
} else {
/* error-handler-404 is back and has generated content */
/* if Status: was set, take it otherwise use 200 */
}
} else if (con->http_status >= 400) {
buffer *error_handler = NULL;
if (!buffer_string_is_empty(con->conf.error_handler)) {
error_handler = con->conf.error_handler;
} else if ((con->http_status == 404 || con->http_status == 403)
&& !buffer_string_is_empty(con->conf.error_handler_404)) {
error_handler = con->conf.error_handler_404;
}
if (con->in_error_handler == 0 &&
(!buffer_string_is_empty(con->conf.error_handler) ||
!buffer_string_is_empty(con->error_handler))) {
if (error_handler) {
/* call error-handler */
con->error_handler_saved_status = con->http_status;
con->http_status = 0;
/* set REDIRECT_STATUS to save current HTTP status code
* for access by dynamic handlers
* https://redmine.lighttpd.net/issues/1828 */
data_string *ds;
if (NULL == (ds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
ds = data_string_init();
}
buffer_copy_string_len(ds->key, CONST_STR_LEN("REDIRECT_STATUS"));
buffer_append_int(ds->value, con->http_status);
array_insert_unique(con->environment, (data_unset *)ds);
if (error_handler == con->conf.error_handler) {
plugins_call_connection_reset(srv, con);
if (con->request.content_length) {
if ((off_t)con->request.content_length != chunkqueue_length(con->request_content_queue)) {
con->keep_alive = 0;
}
con->request.content_length = 0;
chunkqueue_reset(con->request_content_queue);
}
if (buffer_string_is_empty(con->error_handler)) {
buffer_copy_buffer(con->request.uri, con->conf.error_handler);
} else {
buffer_copy_buffer(con->request.uri, con->error_handler);
con->is_writable = 1;
con->file_finished = 0;
con->file_started = 0;
con->got_response = 0;
con->parsed_response = 0;
con->response.keep_alive = 0;
con->response.content_length = -1;
con->response.transfer_encoding = 0;
array_reset(con->response.headers);
chunkqueue_reset(con->write_queue);
array_set_key_value(con->environment, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.orig_uri));
con->error_handler_saved_status = con->http_status;
con->error_handler_saved_method = con->request.http_method;
con->request.http_method = HTTP_METHOD_GET;
} else { /*(preserve behavior for server.error-handler-404)*/
array_set_key_value(con->environment, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(error_handler));
con->error_handler_saved_status = -con->http_status; /*(negative to flag old behavior)*/
}
con->http_status = 0;
buffer_copy_buffer(con->request.uri, error_handler);
buffer_reset(con->physical.path);
connection_handle_errdoc_init(con);
con->in_error_handler = 1;
done = -1;
break;
} else if (con->in_error_handler) {
/* error-handler is a 404 */
con->http_status = con->error_handler_saved_status;
}
} else if (con->in_error_handler) {
/* error-handler is back and has generated content */
/* if Status: was set, take it otherwise use 200 */
}
}
if (con->http_status == 0) con->http_status = 200;

@ -1078,15 +1078,21 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_
if (!buffer_string_is_empty(con->request.pathinfo)) {
cgi_env_add(&env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
}
cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
if (!buffer_string_is_empty(con->uri.query)) {
cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
} else {
cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
}
if (!buffer_string_is_empty(con->request.orig_uri)) {
if (con->error_handler_saved_status >= 0) {
cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.uri));
} else {
cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
}
/* set REDIRECT_STATUS for php compiled with --force-redirect
* (if REDIRECT_STATUS has not already been set by error handler) */
if (0 == con->error_handler_saved_status) {
cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
}
switch (con->dst_addr.plain.sa_family) {

@ -1864,6 +1864,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
fcgi_extension_host *host= hctx->host;
connection *con = hctx->remote_conn;
buffer * const req_uri = (con->error_handler_saved_status >= 0) ? con->request.uri : con->request.orig_uri;
server_socket *srv_sock = con->srv_socket;
sock_addr our_addr;
@ -2026,26 +2027,24 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
* /index/list
*
*/
if ('/' != host->strip_request_uri->ptr[buffer_string_length(host->strip_request_uri) - 1]) {
/* fix the user-input to have / as last char */
buffer_append_string_len(host->strip_request_uri, CONST_STR_LEN("/"));
}
if (buffer_string_length(con->request.orig_uri) >= buffer_string_length(host->strip_request_uri) &&
0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, buffer_string_length(host->strip_request_uri))) {
if (buffer_string_length(req_uri) >= buffer_string_length(host->strip_request_uri) &&
0 == strncmp(req_uri->ptr, host->strip_request_uri->ptr, buffer_string_length(host->strip_request_uri))) {
/* the left is the same */
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
con->request.orig_uri->ptr + (buffer_string_length(host->strip_request_uri) - 1),
buffer_string_length(con->request.orig_uri) - (buffer_string_length(host->strip_request_uri) - 1)), con);
req_uri->ptr + (buffer_string_length(host->strip_request_uri) - 1),
buffer_string_length(req_uri) - (buffer_string_length(host->strip_request_uri) - 1)), con)
} else {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)),con)
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(req_uri)),con)
}
} else {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)),con)
}
if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri)),con)
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(req_uri)),con)
}
if (!buffer_string_is_empty(con->uri.query)) {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query)),con)
@ -2056,7 +2055,11 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
s = get_http_method_name(con->request.http_method);
force_assert(s);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s)),con)
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")),con) /* if php is compiled with --force-redirect */
/* set REDIRECT_STATUS for php compiled with --force-redirect
* (if REDIRECT_STATUS has not already been set by error handler) */
if (0 == con->error_handler_saved_status) {
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")), con);
}
s = get_http_version_name(con->request.http_version);
force_assert(s);
FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)),con)

@ -1015,6 +1015,12 @@ static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, bu
result = HANDLER_FINISHED;
} else if (MAGNET_RESTART_REQUEST == lua_return_value) {
if (!buffer_is_equal(con->request.uri, con->request.orig_uri)
&& !array_get_element(con->environment, "REDIRECT_URI")) {
array_set_key_value(con->environment,
CONST_STR_LEN("REDIRECT_URI"),
CONST_BUF_LEN(con->request.orig_uri));
}
result = HANDLER_COMEBACK;
}
@ -1027,6 +1033,7 @@ static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, bu
static handler_t magnet_attract_array(server *srv, connection *con, plugin_data *p, array *files) {
size_t i;
handler_t ret = HANDLER_GO_ON;
/* no filename set */
if (files->used == 0) return HANDLER_GO_ON;
@ -1034,18 +1041,25 @@ static handler_t magnet_attract_array(server *srv, connection *con, plugin_data
/**
* execute all files and jump out on the first !HANDLER_GO_ON
*/
for (i = 0; i < files->used; i++) {
for (i = 0; i < files->used && ret == HANDLER_GO_ON; i++) {
data_string *ds = (data_string *)files->data[i];
handler_t ret;
if (buffer_string_is_empty(ds->value)) continue;
ret = magnet_attract(srv, con, p, ds->value);
}
if (ret != HANDLER_GO_ON) return ret;
if (con->error_handler_saved_status) {
/* retrieve (possibly modified) REDIRECT_STATUS and store as number */
unsigned long x;
data_string * const ds = (data_string *)array_get_element(con->environment, "REDIRECT_STATUS");
if (ds && (x = strtoul(ds->value->ptr, NULL, 10)) < 1000)
/*(simplified validity check x < 1000)*/
con->error_handler_saved_status =
con->error_handler_saved_status > 0 ? (int)x : -(int)x;
}
return HANDLER_GO_ON;
return ret;
}
URIHANDLER_FUNC(mod_magnet_uri_handler) {

@ -444,6 +444,13 @@ static handler_t process_rewrite_rules(server *srv, connection *con, plugin_data
if (rule->once) hctx->state = REWRITE_STATE_FINISHED;
if (!buffer_is_equal(con->request.uri, con->request.orig_uri)
&& !array_get_element(con->environment, "REDIRECT_URI")) {
array_set_key_value(con->environment,
CONST_STR_LEN("REDIRECT_URI"),
CONST_BUF_LEN(con->request.orig_uri));
}
return HANDLER_COMEBACK;
}
#undef N

@ -1648,9 +1648,10 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir));
}
scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
if (!buffer_is_equal(con->request.uri, con->request.orig_uri)) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_URI"), CONST_BUF_LEN(con->request.uri));
if (con->error_handler_saved_status >= 0) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.uri));
} else {
scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
}
if (!buffer_string_is_empty(con->uri.query)) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
@ -1661,7 +1662,11 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
s = get_http_method_name(con->request.http_method);
force_assert(s);
scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
/* set REDIRECT_STATUS for php compiled with --force-redirect
* (if REDIRECT_STATUS has not already been set by error handler) */
if (0 == con->error_handler_saved_status) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
}
s = get_http_version_name(con->request.http_version);
force_assert(s);
scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));

@ -290,8 +290,12 @@ static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), buffer_is_empty(con->uri.query) ? "" : con->uri.query->ptr);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
/* set REDIRECT_STATUS for php compiled with --force-redirect
* (if REDIRECT_STATUS has not already been set by error handler) */
if (0 == con->error_handler_saved_status) {
ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
}
ssi_env_add_request_headers(srv, con, p);

@ -343,6 +343,7 @@ static void server_free(server *srv) {
buffer_free(s->ssl_dh_file);
buffer_free(s->ssl_ec_curve);
buffer_free(s->error_handler);
buffer_free(s->error_handler_404);
buffer_free(s->errorfile_prefix);
array_free(s->mimetypes);
buffer_free(s->ssl_verifyclient_username);

@ -37,6 +37,9 @@ cgi.assign = (
$HTTP["url"] =~ "^/static/" {
server.error-handler-404 = "/404.html"
}
else $HTTP["url"] =~ "^/dynamic/redirect_status/" {
server.error-handler = "/404.pl"
}
else $HTTP["url"] =~ "." {
server.error-handler-404 = "/404.pl"
}

@ -18,7 +18,7 @@ BEGIN {
use strict;
use IO::Socket;
use Test::More tests => 8;
use Test::More tests => 9;
use LightyTest;
my $tf = LightyTest->new();
@ -58,6 +58,13 @@ EOF
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'HTTP-Content' => "Not found here\n" } ];
ok($tf->handle_http($t) == 0, '404 handler => dynamic(404)');
$t->{REQUEST} = ( <<EOF
GET /dynamic/redirect_status/ HTTP/1.0
EOF
);
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'HTTP-Content' => "REDIRECT_STATUS\n" } ];
ok($tf->handle_http($t) == 0, 'error handler => dynamic(REDIRECT_STATUS)');
$t->{REQUEST} = ( <<EOF
GET /dynamic/nostatus/notfound HTTP/1.0
EOF

@ -3,8 +3,10 @@
use CGI qw/:standard/;
my $cgi = new CGI;
my $request_uri = $ENV{'REQUEST_URI'};
print (STDERR "REQUEST_URI: $request_uri\n");
my $request_uri = $ENV{'REQUEST_URI'}; # server.error-handler-404
my $redirect_uri= $ENV{'REDIRECT_URI'}; # server.error-handler
print (STDERR "REQUEST_URI: $request_uri\n");
print (STDERR "REDIRECT_URI: $redirect_uri\n");
if ($request_uri =~ m/^\/dynamic\/200\// ) {
print header ( -status => 200,
@ -28,6 +30,11 @@ elsif ($request_uri =~ m/^\/send404\.pl/ ) {
elsif ($request_uri =~ m/^\/dynamic\/nostatus\// ) {
print ("found here\n");
}
elsif ($redirect_uri =~ m/^\/dynamic\/redirect_status\// ) {
print header ( -status => $ENV{'REDIRECT_STATUS'},
-type => 'text/plain');
print ("REDIRECT_STATUS\n");
}
else {
print header ( -status => 500,
-type => 'text/plain');

Loading…
Cancel
Save