diff --git a/CHANGELOG.md b/CHANGELOG.md index ff64086c9..710b8e2a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Add webserver logging controls to Usermin Configuration module * Add option to rotate Webmin and Usermin webserver logs using `logrotate` instead of periodically clearing them [#2821](https://github.com/webmin/webmin/pull/2821) * Add DNF 4 and 5 package hold management to the Software Package Updates module +* Add `return` based redirects with 301, 302, 303, 307 and 308 codes to the URL Re-Writing pages in the Nginx Webserver module [forum.virtualmin.com/t/137940](https://forum.virtualmin.com/t/137940) * Fix DNF update confirmations by previewing packages and dependencies that will be installed or updated * Fix PostgreSQL initialization on EL systems to use SCRAM-SHA-256 authentication by default * Fix IPsec host key generation with modern Libreswan [#2132](https://github.com/webmin/webmin/issues/2132) diff --git a/nginx/edit_lrewrite.cgi b/nginx/edit_lrewrite.cgi index 02af0ebda..fadd0528f 100755 --- a/nginx/edit_lrewrite.cgi +++ b/nginx/edit_lrewrite.cgi @@ -23,6 +23,8 @@ print &ui_table_start($text{'rewrite_header'}, undef, 2); print &nginx_rewrite_input("rewrite", $location); +print &nginx_return_input("return", $location); + print &nginx_onoff_input("rewrite_log", $location); print &ui_table_end(); diff --git a/nginx/edit_srewrite.cgi b/nginx/edit_srewrite.cgi index 3623859f4..b0c5b6b3b 100755 --- a/nginx/edit_srewrite.cgi +++ b/nginx/edit_srewrite.cgi @@ -19,6 +19,8 @@ print &ui_table_start($text{'rewrite_header'}, undef, 2); print &nginx_rewrite_input("rewrite", $server); +print &nginx_return_input("return", $server); + print &nginx_onoff_input("rewrite_log", $server); print &ui_table_end(); diff --git a/nginx/lang/en b/nginx/lang/en index d8f6f919a..c77639bab 100644 --- a/nginx/lang/en +++ b/nginx/lang/en @@ -324,6 +324,17 @@ rewrite_redirect=Return 302 redirect rewrite_permanent=Return 301 redirect rewrite_efrom=Source path $1 contains spaces rewrite_eto=Destination URL $1 is missing or contains spaces +opt_return=Redirect all requests +rewrite_return_none=No redirect +rewrite_return_to=to +rewrite_return_eg=/uri or https://example.com$request_uri +rewrite_return_301=301 (Moved permanently) +rewrite_return_302=302 (Found) +rewrite_return_303=303 (See other) +rewrite_return_307=307 (Temporary redirect) +rewrite_return_308=308 (Permanent redirect) +rewrite_ereturn=Redirect URL is missing or contains spaces +rewrite_ereturncode=Invalid redirect HTTP code location_create=Create Location location_edit=Edit Location diff --git a/nginx/nginx-lib.pl b/nginx/nginx-lib.pl index 77d4b27e6..f69b079d1 100644 --- a/nginx/nginx-lib.pl +++ b/nginx/nginx-lib.pl @@ -1462,6 +1462,75 @@ for(my $i=0; defined(my $from = $in->{$name."_from_".$i}); $i++) { &save_directive($parent, $name, \@obj); } +# list_return_redirect_codes() +# Returns the HTTP codes that the return directive accepts with a URL +sub list_return_redirect_codes +{ +return ( 301, 302, 303, 307, 308 ); +} + +# get_return_redirect(&object) +# Returns the code and URL of a return directive if it is a redirect, or an +# empty list for other uses such as return 404 +sub get_return_redirect +{ +my ($obj) = @_; +my @w = @{$obj->{'words'}}; +if (@w == 2 && &indexof($w[0], &list_return_redirect_codes()) >= 0) { + return @w; + } +elsif (@w == 1 && $w[0] =~ /^(https?:\/\/|\$scheme)/) { + # Single URL form defaults to a 302 redirect + return ( 302, $w[0] ); + } +return ( ); +} + +# nginx_return_input(name, &parent) +# Returns HTML for a redirect via the return directive +sub nginx_return_input +{ +my ($name, $parent) = @_; +return undef if (!&supported_directive($name, $parent)); +my $obj = &find($name, $parent); +my ($code, $url) = $obj ? &get_return_redirect($obj) : ( ); +# Leave a return directive that is not a redirect alone +return undef if ($obj && !$code); +my $sel = &ui_select($name."_code", $code || 301, + [ map { [ $_, $text{'rewrite_return_'.$_} ] } + &list_return_redirect_codes() ]); +return &ui_table_row($text{'opt_'.$name}, + &ui_opt_textbox($name, $url, 50, $text{'rewrite_return_none'}, + $sel." ".$text{'rewrite_return_to'}." ", 0, + [ $name."_code" ], undef, + "placeholder=\"". + "e_escape($text{'rewrite_return_eg'})."\""), 3); +} + +# nginx_return_parse(name, &parent, &in) +# Updates the config with input from nginx_return_input +sub nginx_return_parse +{ +my ($name, $parent, $in) = @_; +return undef if (!&supported_directive($name, $parent)); +$in ||= \%in; +my $obj = &find($name, $parent); +# Never touch a return directive that was not shown in the form +return undef if ($obj && !&get_return_redirect($obj)); +if ($in->{$name."_def"}) { + &save_directive($parent, $name, [ ]); + } +else { + my $code = $in->{$name."_code"}; + &indexof($code, &list_return_redirect_codes()) >= 0 || + &error($text{'rewrite_ereturncode'}); + my $url = $in->{$name}; + $url =~ /^\S+$/ || &error($text{'rewrite_ereturn'}); + &save_directive($parent, $name, [ { 'name' => $name, + 'words' => [ $code, $url ] } ]); + } +} + # list_log_formats([&server]) # Returns a list of all log format names sub list_log_formats diff --git a/nginx/save_lrewrite.cgi b/nginx/save_lrewrite.cgi index 619a98f85..4bf090eb7 100755 --- a/nginx/save_lrewrite.cgi +++ b/nginx/save_lrewrite.cgi @@ -16,6 +16,8 @@ $location || &error($text{'location_egone'}); &nginx_rewrite_parse("rewrite", $location); +&nginx_return_parse("return", $location); + &nginx_onoff_parse("rewrite_log", $location); &flush_config_file_lines(); diff --git a/nginx/save_srewrite.cgi b/nginx/save_srewrite.cgi index f7ecb3e7f..a7b2368c4 100755 --- a/nginx/save_srewrite.cgi +++ b/nginx/save_srewrite.cgi @@ -14,6 +14,8 @@ $server || &error($text{'server_egone'}); &nginx_rewrite_parse("rewrite", $server); +&nginx_return_parse("return", $server); + &nginx_onoff_parse("rewrite_log", $server); &flush_config_file_lines();