diff options
-rw-r--r-- | src/base.h | 2 | ||||
-rw-r--r-- | src/configfile.c | 10 | ||||
-rw-r--r-- | src/connections.c | 57 | ||||
-rw-r--r-- | src/mod_cgi.c | 4 | ||||
-rw-r--r-- | src/mod_fastcgi.c | 17 | ||||
-rw-r--r-- | src/mod_magnet.c | 16 | ||||
-rw-r--r-- | src/mod_scgi.c | 7 | ||||
-rw-r--r-- | src/server.c | 1 | ||||
-rw-r--r-- | tests/404-handler.conf | 3 | ||||
-rwxr-xr-x | tests/core-404-handler.t | 9 | ||||
-rwxr-xr-x | tests/docroot/www/404.pl | 11 |
11 files changed, 108 insertions, 29 deletions
@@ -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'); |