summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/base.h2
-rw-r--r--src/configfile.c10
-rw-r--r--src/connections.c57
-rw-r--r--src/mod_cgi.c4
-rw-r--r--src/mod_fastcgi.c17
-rw-r--r--src/mod_magnet.c16
-rw-r--r--src/mod_scgi.c7
-rw-r--r--src/server.c1
-rw-r--r--tests/404-handler.conf3
-rwxr-xr-xtests/core-404-handler.t9
-rwxr-xr-xtests/docroot/www/404.pl11
11 files changed, 108 insertions, 29 deletions
diff --git a/src/base.h b/src/base.h
index 5d4ea35e..1111d769 100644
--- a/src/base.h
+++ b/src/base.h
@@ -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;
@@ -447,6 +448,7 @@ typedef struct {
/* error-handler */
int error_handler_saved_status;
+ http_method_t error_handler_saved_method;
struct server_socket *srv_socket; /* reference to the server-socket */
diff --git a/src/configfile.c b/src/configfile.c
index 1a0f3dbe..28a1c613 100644
--- a/src/configfile.c
+++ b/src/configfile.c
@@ -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"))) {
diff --git a/src/connections.c b/src/connections.c
index 8e1990a5..d9aaaebf 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -632,6 +632,8 @@ int connection_reset(server *srv, connection *con) {
con->header_len = 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);
@@ -1021,19 +1023,30 @@ 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->error_handler_saved_status) {
- if (con->http_status == 404 || con->http_status == 403) {
- /* error-handler-404 is a 404 */
+ 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 == 404 || con->http_status == 403) {
- /* 404 error-handler */
-
+ } 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 (error_handler) {
/* call error-handler */
/* set REDIRECT_STATUS to save current HTTP status code
@@ -1047,10 +1060,40 @@ int connection_state_machine(server *srv, connection *con) {
buffer_append_int(ds->value, con->http_status);
array_insert_unique(con->environment, (data_unset *)ds);
- con->error_handler_saved_status = con->http_status;
+ 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);
+ }
+
+ 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, con->conf.error_handler);
+ buffer_copy_buffer(con->request.uri, error_handler);
buffer_reset(con->physical.path);
connection_handle_errdoc_init(con);
diff --git a/src/mod_cgi.c b/src/mod_cgi.c
index 38b4b023..c6f70b90 100644
--- a/src/mod_cgi.c
+++ b/src/mod_cgi.c
@@ -1083,7 +1083,9 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, handler_
} 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
diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
index 9b0ace15..73b9de71 100644
--- a/src/mod_fastcgi.c
+++ b/src/mod_fastcgi.c
@@ -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)
diff --git a/src/mod_magnet.c b/src/mod_magnet.c
index 260cf425..db7b7a0f 100644
--- a/src/mod_magnet.c
+++ b/src/mod_magnet.c
@@ -1027,6 +1027,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 +1035,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) {
diff --git a/src/mod_scgi.c b/src/mod_scgi.c
index e6ecbc0c..5c2fcfe5 100644
--- a/src/mod_scgi.c
+++ b/src/mod_scgi.c
@@ -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));
diff --git a/src/server.c b/src/server.c
index 3128013e..e3c680ad 100644
--- a/src/server.c
+++ b/src/server.c
@@ -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);
diff --git a/tests/404-handler.conf b/tests/404-handler.conf
index e07ff3f9..e10a2697 100644
--- a/tests/404-handler.conf
+++ b/tests/404-handler.conf
@@ -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"
}
diff --git a/tests/core-404-handler.t b/tests/core-404-handler.t
index 599ade20..a7259ae7 100755
--- a/tests/core-404-handler.t
+++ b/tests/core-404-handler.t
@@ -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();
@@ -59,6 +59,13 @@ $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'HTTP-
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
);
diff --git a/tests/docroot/www/404.pl b/tests/docroot/www/404.pl
index 9486ed66..0c0668a3 100755
--- a/tests/docroot/www/404.pl
+++ b/tests/docroot/www/404.pl
@@ -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');