mirror of
https://github.com/webmin/webmin.git
synced 2026-06-04 20:30:22 +01:00
Add site state toggles and proxy-aware server list
https://github.com/webmin/webmin/issues/2688
This commit is contained in:
@@ -6,11 +6,61 @@ use warnings;
|
||||
require './nginx-lib.pl';
|
||||
our (%text, %in, %config, %access);
|
||||
&ReadParse();
|
||||
&error_setup($text{'delete_err'});
|
||||
my @items = split(/\0/, $in{'d'} || "");
|
||||
my $file_action = $in{'toggle'} ? "toggle" :
|
||||
$in{'enable'} ? "enable" :
|
||||
$in{'disable'} ? "disable" : undef;
|
||||
&error_setup($file_action ? $text{'enable_err'} : $text{'delete_err'});
|
||||
$access{'edit'} || &error($text{'server_ecannotedit'});
|
||||
|
||||
my @ids = split(/\0/, $in{'d'} || "");
|
||||
@ids || &error($text{'delete_enone'});
|
||||
if ($file_action) {
|
||||
&can_manage_server_files() || &error($text{'enable_elinkdir'});
|
||||
my %add_to = map { $_, 1 } &get_add_to_files();
|
||||
my %files;
|
||||
foreach my $item (@items) {
|
||||
my $file;
|
||||
if ($item =~ /^file\t([^\t]+)/) {
|
||||
$file = $1;
|
||||
}
|
||||
else {
|
||||
my $server = &find_server($item);
|
||||
next if (!$server || !&can_edit_server($server));
|
||||
$file = $server->{'file'};
|
||||
}
|
||||
my $rfile = $file ? &resolve_links($file) : undef;
|
||||
$files{$rfile}++ if ($rfile && -f $rfile && $add_to{$rfile} &&
|
||||
&can_manage_server_file($rfile));
|
||||
}
|
||||
my @files = keys %files;
|
||||
@files || &error($text{'enable_enone'});
|
||||
foreach my $file (@files) {
|
||||
my $err = $file_action eq "toggle" ?
|
||||
&server_file_enabled($file) ?
|
||||
&disable_server_file($file) :
|
||||
&enable_server_file($file) :
|
||||
$file_action eq "enable" ?
|
||||
&enable_server_file($file) :
|
||||
&disable_server_file($file);
|
||||
$err && &error($err);
|
||||
}
|
||||
&webmin_log($file_action, "serverfile", scalar(@files));
|
||||
&redirect("");
|
||||
exit;
|
||||
}
|
||||
if (!$in{'delete'}) {
|
||||
&error($text{'delete_eaction'});
|
||||
}
|
||||
|
||||
my (@ids, %file_lines);
|
||||
foreach my $item (@items) {
|
||||
if ($item =~ /^file\t([^\t]+)\t(\d+)$/) {
|
||||
push(@{$file_lines{$1}}, $2);
|
||||
}
|
||||
elsif ($item !~ /^file\t/) {
|
||||
push(@ids, $item);
|
||||
}
|
||||
}
|
||||
@ids || %file_lines || &error($text{'delete_enone'});
|
||||
|
||||
# Validate the selected server blocks before locking config files.
|
||||
foreach my $id (@ids) {
|
||||
@@ -19,36 +69,54 @@ foreach my $id (@ids) {
|
||||
&can_edit_server($server) || &error($text{'server_ecannot'});
|
||||
&is_default_server_block($server) && &error($text{'delete_edefault'});
|
||||
}
|
||||
my %add_to = map { $_, 1 } &get_add_to_files();
|
||||
my %file_servers;
|
||||
foreach my $file (keys %file_lines) {
|
||||
my $rfile = &resolve_links($file);
|
||||
next if (!$rfile || !-f $rfile || !$add_to{$rfile} ||
|
||||
!&can_manage_server_file($rfile));
|
||||
my @servers = &find_servers_in_file($rfile);
|
||||
foreach my $line (@{$file_lines{$file}}) {
|
||||
my ($server) = grep { $_->{'line'} == $line } @servers;
|
||||
$server || &error($text{'server_egone'});
|
||||
&can_edit_server($server) || &error($text{'server_ecannot'});
|
||||
&is_default_server_block($server) && &error($text{'delete_edefault'});
|
||||
push(@{$file_servers{$rfile}}, $server);
|
||||
}
|
||||
}
|
||||
@ids || %file_servers || &error($text{'delete_enone'});
|
||||
|
||||
&lock_all_config_files();
|
||||
my $conf = &get_config();
|
||||
my $http = &find("http", $conf);
|
||||
if (!$http) {
|
||||
&unlock_all_config_files();
|
||||
&error(&text('index_ehttp', "<tt>$config{'nginx_config'}</tt>"));
|
||||
}
|
||||
my @servers;
|
||||
foreach my $id (@ids) {
|
||||
my $server = &find_server($id);
|
||||
if (!$server) {
|
||||
if (@ids) {
|
||||
&lock_all_config_files();
|
||||
my $conf = &get_config();
|
||||
my $http = &find("http", $conf);
|
||||
if (!$http) {
|
||||
&unlock_all_config_files();
|
||||
&error($text{'server_egone'});
|
||||
&error(&text('index_ehttp', "<tt>$config{'nginx_config'}</tt>"));
|
||||
}
|
||||
if (!&can_edit_server($server)) {
|
||||
&unlock_all_config_files();
|
||||
&error($text{'server_ecannot'});
|
||||
foreach my $id (@ids) {
|
||||
my $server = &find_server($id);
|
||||
if (!$server) {
|
||||
&unlock_all_config_files();
|
||||
&error($text{'server_egone'});
|
||||
}
|
||||
if (!&can_edit_server($server)) {
|
||||
&unlock_all_config_files();
|
||||
&error($text{'server_ecannot'});
|
||||
}
|
||||
if (&is_default_server_block($server)) {
|
||||
&unlock_all_config_files();
|
||||
&error($text{'delete_edefault'});
|
||||
}
|
||||
push(@servers, $server);
|
||||
}
|
||||
if (&is_default_server_block($server)) {
|
||||
&unlock_all_config_files();
|
||||
&error($text{'delete_edefault'});
|
||||
foreach my $server (@servers) {
|
||||
&save_directive($http, [ $server ], [ ]);
|
||||
}
|
||||
push(@servers, $server);
|
||||
&flush_config_file_lines();
|
||||
&unlock_all_config_files();
|
||||
}
|
||||
foreach my $server (@servers) {
|
||||
&save_directive($http, [ $server ], [ ]);
|
||||
}
|
||||
&flush_config_file_lines();
|
||||
&unlock_all_config_files();
|
||||
foreach my $server (@servers) {
|
||||
&delete_server_link($server);
|
||||
}
|
||||
@@ -57,5 +125,12 @@ foreach my $server (@servers) {
|
||||
next if ($done_file{$server->{'file'}}++);
|
||||
&delete_server_file_if_empty($server);
|
||||
}
|
||||
&webmin_log("delete", "servers", scalar(@servers));
|
||||
foreach my $file (keys %file_servers) {
|
||||
&lock_file($file);
|
||||
&delete_servers_from_file($file, @{$file_servers{$file}});
|
||||
&unlock_file($file);
|
||||
}
|
||||
my $count = scalar(@servers) +
|
||||
scalar(map { @$_ } values %file_servers);
|
||||
&webmin_log("delete", "servers", $count);
|
||||
&redirect("");
|
||||
|
||||
101
nginx/index.cgi
101
nginx/index.cgi
@@ -60,21 +60,45 @@ if ($access{'global'}) {
|
||||
# Show list of server blocks
|
||||
print &ui_tabs_start_tab("mode", "list");
|
||||
my @allservers = &find("server", $http);
|
||||
my @servers = grep { &can_edit_server($_) } @allservers;
|
||||
if (@servers) {
|
||||
my $can_files = &can_manage_server_files();
|
||||
my @add_to_files = $can_files ? &get_add_to_files() : ( );
|
||||
my %add_to_file = map { $_, 1 } @add_to_files;
|
||||
my @rows = &get_server_list_rows($http);
|
||||
if (@rows) {
|
||||
my $can_delete = $access{'edit'};
|
||||
my $has_proxy;
|
||||
foreach my $r (@rows) {
|
||||
my (undef, $proxy) = &server_root_proxy_state($r->{'server'});
|
||||
$has_proxy ||= $proxy;
|
||||
}
|
||||
my @heads = ( $can_delete ? ( "" ) : ( ),
|
||||
$text{'index_name'},
|
||||
$text{'index_ip'},
|
||||
$text{'index_port'},
|
||||
$text{'index_root'} );
|
||||
$text{'index_root'},
|
||||
$has_proxy ? ( $text{'index_proxytarget'} ) : ( ),
|
||||
$can_files ? ( $text{'index_status'} ) : ( ),
|
||||
$text{'index_url'} );
|
||||
my @data;
|
||||
foreach my $s (@servers) {
|
||||
foreach my $r (@rows) {
|
||||
my $s = $r->{'server'};
|
||||
my $name = &find_value("server_name", $s);
|
||||
$name ||= "";
|
||||
my $default = &is_default_server_block($s);
|
||||
my $showname = !$default ?
|
||||
&html_escape($name) : $text{'default_server_block'};
|
||||
my $id = &server_id($s);
|
||||
my $name_sort = ($default ? "0 " : "1 ").
|
||||
lc($default ? $text{'default_server_block'} : $name);
|
||||
my $name_sort_html = &html_escape($name_sort);
|
||||
my $name_sort_span =
|
||||
"<span style='position:absolute;left:-10000px;".
|
||||
"width:1px;height:1px;overflow:hidden' ".
|
||||
"aria-hidden='true'>$name_sort_html</span>";
|
||||
my $shownamelink = $r->{'active'} ?
|
||||
$name_sort_span."<a href='edit_server.cgi?id=".
|
||||
&urlize($id)."'>".$showname."</a>" :
|
||||
$name_sort_span.$showname;
|
||||
|
||||
# Extract all IPs and ports from listen directives
|
||||
my (@ips, @ports);
|
||||
@@ -86,43 +110,66 @@ if (@servers) {
|
||||
push(@ports, $port);
|
||||
}
|
||||
|
||||
my $rootdir = &find_value("root", $s);
|
||||
my $root = $rootdir;
|
||||
if (!$root) {
|
||||
my @locs = &find("location", $s);
|
||||
my ($rootloc) = grep { $_->{'value'} eq '/' } @locs;
|
||||
if ($rootloc) {
|
||||
$rootdir = &find_value("root", $rootloc);
|
||||
$root = $rootdir ||
|
||||
"<i>$text{'index_noroot'}</i>";
|
||||
my @cols;
|
||||
my $status = "";
|
||||
if ($can_files) {
|
||||
if ($add_to_file{$r->{'file'}}) {
|
||||
my $enabled = &server_file_enabled($r->{'file'});
|
||||
$status = $enabled ? $text{'index_enabled'} :
|
||||
$text{'index_disabled'};
|
||||
}
|
||||
else {
|
||||
$root = "<i>$text{'index_norootloc'}</i>";
|
||||
}
|
||||
$rootdir ||= "";
|
||||
}
|
||||
my $id = $name.";".$rootdir;
|
||||
my @cols = (
|
||||
"<a href='edit_server.cgi?id=".&urlize($id)."'>".
|
||||
$showname."</a>",
|
||||
push(@cols, { 'type' => 'string',
|
||||
'value' => $shownamelink,
|
||||
'td' => "data-sort='$name_sort_html' ".
|
||||
"data-order='$name_sort_html'" });
|
||||
push(@cols,
|
||||
join("<br>", @ips),
|
||||
join("<br>", @ports),
|
||||
$root );
|
||||
if ($can_delete && !$default) {
|
||||
&server_root_summary($s) );
|
||||
push(@cols, &server_proxy_summary($s)) if ($has_proxy);
|
||||
push(@cols, $status) if ($can_files);
|
||||
my $url = $r->{'active'} ? &server_url($s) : undef;
|
||||
push(@cols, $url ? &ui_link("e_escape($url),
|
||||
$text{'index_view'}, undef,
|
||||
'target="_blank" rel="noopener noreferrer"') : "");
|
||||
if ($can_delete && $r->{'active'} && !$default) {
|
||||
unshift(@cols, { 'type' => 'checkbox',
|
||||
'name' => 'd',
|
||||
'value' => $id });
|
||||
}
|
||||
elsif ($can_delete && $can_files && !$r->{'active'} &&
|
||||
!$default && $add_to_file{$r->{'file'}}) {
|
||||
unshift(@cols, { 'type' => 'checkbox',
|
||||
'name' => 'd',
|
||||
'value' => "file\t".$r->{'file'}.
|
||||
"\t".$s->{'line'} });
|
||||
}
|
||||
elsif ($can_delete) {
|
||||
unshift(@cols, "");
|
||||
}
|
||||
push(@data, \@cols);
|
||||
}
|
||||
if ($can_delete) {
|
||||
print &ui_form_columns_table(
|
||||
"delete_servers.cgi",
|
||||
[ [ "delete", $text{'index_delete'} ] ],
|
||||
1, [ ], [ ], \@heads, 100, \@data);
|
||||
my $list_form = "server_blocks_form";
|
||||
my $has_checkbox = grep {
|
||||
ref($_->[0]) && $_->[0]->{'type'} eq 'checkbox'
|
||||
} @data;
|
||||
my $links = $has_checkbox ?
|
||||
&ui_links_row([ &select_all_link("d", 0),
|
||||
&select_invert_link("d", 0) ]) : "";
|
||||
my @left_buttons = ( [ "delete", $text{'index_delete'} ] );
|
||||
my @right_buttons = $can_files ?
|
||||
( [ "toggle", $text{'index_toggle'}, undef, undef,
|
||||
"form=\"$list_form\"" ] ) : ( );
|
||||
print &ui_form_start("delete_servers.cgi", "post", undef,
|
||||
"id='$list_form'");
|
||||
print $links;
|
||||
print &ui_columns_table(\@heads, 100, \@data);
|
||||
print $links;
|
||||
print &ui_form_end_side_by_side($list_form,
|
||||
\@left_buttons,
|
||||
\@right_buttons);
|
||||
}
|
||||
else {
|
||||
print &ui_columns_table(\@heads, 100, \@data);
|
||||
|
||||
@@ -2,15 +2,22 @@ index_version=Nginx version $1
|
||||
index_econfig=The Nginx configuration file $1 was not found on your system. Use the <a href='$2'>module configuration</a> page to enter the correct path.
|
||||
index_ecmd=The Nginx command $1 was not found on your system. Use the <a href='$2'>module configuration</a> page to enter the correct path.
|
||||
index_ehttp=No <tt>http</tt> section was found in your Nginx config file $1. Maybe it is not setup as a webserver?
|
||||
index_name=Server block name
|
||||
index_name=Server Block Name
|
||||
default_server_block=Default Server
|
||||
index_ip=IP addresses
|
||||
index_port=Port numbers
|
||||
index_root=Root directory
|
||||
index_status=State
|
||||
index_ip=Address
|
||||
index_port=Port
|
||||
index_root=Root Directory
|
||||
index_proxytarget=Proxy Target
|
||||
index_url=URL
|
||||
index_view=Open..
|
||||
index_toggle=Toggle State
|
||||
index_enabled=Enabled
|
||||
index_disabled=Disabled
|
||||
index_any=Any IPv4 address
|
||||
index_any6=Any IPv6 address
|
||||
index_noroot=No root location
|
||||
index_norootloc=Not a directory
|
||||
index_noroot=No root directory
|
||||
index_noproxy=No proxy target
|
||||
index_none=No server blocks have been created yet.
|
||||
index_noneaccess=No server blocks that you have access to have been created yet.
|
||||
index_add=Add a new Nginx server block.
|
||||
@@ -200,8 +207,17 @@ server_eclash=A server block with the same name already exists
|
||||
server_pp=Proxy to $1
|
||||
server_eexist=No Nginx server found
|
||||
delete_err=Failed to delete server blocks
|
||||
delete_eaction=No action was selected
|
||||
delete_enone=No server blocks were selected to delete
|
||||
delete_edefault=The default server block cannot be deleted
|
||||
enable_err=Failed to change server file status
|
||||
enable_enone=No manageable server files were selected
|
||||
enable_efile=Server file does not exist or cannot be managed
|
||||
enable_elinkdir=No enabled server-block links directory is configured
|
||||
enable_elink=Failed to create symbolic link $1 : $2
|
||||
enable_eunlink=Failed to remove symbolic link $1 : $2
|
||||
enable_elinkexists=The symbolic link $1 already exists
|
||||
enable_etest=Nginx configuration test failed after changing the server file status : $1
|
||||
|
||||
slogs_title=Server Block Logging
|
||||
slogs_header=Log file options
|
||||
@@ -334,6 +350,10 @@ log_manual=Manually edited config file $1
|
||||
log_create_server=Created server block $1
|
||||
log_modify_server=Modified server block $1
|
||||
log_delete_server=Deleted server block $1
|
||||
log_delete_servers=Deleted $1 server blocks
|
||||
log_toggle_serverfile=Toggled state of $1 server block files
|
||||
log_enable_serverfile=Enabled $1 server block files
|
||||
log_disable_serverfile=Disabled $1 server block files
|
||||
log_slogs_server=Changed logging options for $1
|
||||
log_ssl_server=Change SSL configuration for $1
|
||||
log_sdocs_server=Changed document options for $1
|
||||
|
||||
@@ -26,6 +26,12 @@ elsif ($type eq 'server') {
|
||||
return &text('log_'.$action.'_server',
|
||||
"<tt>".&html_escape($object)."</tt>");
|
||||
}
|
||||
elsif ($type eq 'servers') {
|
||||
return &text('log_'.$action.'_servers', $object);
|
||||
}
|
||||
elsif ($type eq 'serverfile') {
|
||||
return &text('log_'.$action.'_serverfile', $object);
|
||||
}
|
||||
elsif ($type eq 'location') {
|
||||
return &text('log_'.$action.'_location',
|
||||
"<tt>".&html_escape($object)."</tt>",
|
||||
@@ -41,4 +47,3 @@ else {
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
@@ -1530,6 +1530,366 @@ my $out = &backquote_logged("$config{'nginx_cmd'} -t 2>&1 </dev/null");
|
||||
return $? || $out !~ /syntax\s+is\s+ok/ ? $out : undef;
|
||||
}
|
||||
|
||||
# can_manage_server_files()
|
||||
# Returns 1 if this system uses Debian-style available/enabled site dirs
|
||||
sub can_manage_server_files
|
||||
{
|
||||
return $config{'add_to'} && -d $config{'add_to'} &&
|
||||
$config{'add_link'} && -d $config{'add_link'};
|
||||
}
|
||||
|
||||
# get_add_to_files()
|
||||
# Returns config files from the directory used for new server blocks
|
||||
sub get_add_to_files
|
||||
{
|
||||
my @rv;
|
||||
if ($config{'add_to'} && -d $config{'add_to'}) {
|
||||
opendir(ADDTO, $config{'add_to'}) || return @rv;
|
||||
foreach my $f (sort { lc($a) cmp lc($b) } readdir(ADDTO)) {
|
||||
next if ($f eq "." || $f eq "..");
|
||||
my $file = $config{'add_to'}."/".$f;
|
||||
my $rfile = &resolve_links($file);
|
||||
next if (!$rfile || !-f $rfile || !-r $rfile);
|
||||
push(@rv, $rfile);
|
||||
}
|
||||
closedir(ADDTO);
|
||||
}
|
||||
return &unique(@rv);
|
||||
}
|
||||
|
||||
# find_servers_in_file(file)
|
||||
# Returns server blocks parsed from one config file
|
||||
sub find_servers_in_file
|
||||
{
|
||||
my ($file) = @_;
|
||||
my $rfile = &resolve_links($file);
|
||||
$rfile ||= $file;
|
||||
return ( ) if (!-r $rfile);
|
||||
my $conf = &read_config_file($rfile);
|
||||
return grep { $_->{'file'} eq $rfile } &find_recursive("server", $conf);
|
||||
}
|
||||
|
||||
# can_manage_server_file(file)
|
||||
# Returns 1 if all server blocks in a file are manageable by this user
|
||||
sub can_manage_server_file
|
||||
{
|
||||
my ($file) = @_;
|
||||
my $rfile = &resolve_links($file);
|
||||
$rfile ||= $file;
|
||||
return 0 if (!$rfile || !-f $rfile || !-r $rfile);
|
||||
my @servers = &find_servers_in_file($rfile);
|
||||
return 0 if (!@servers);
|
||||
foreach my $server (@servers) {
|
||||
return 0 if (!&can_edit_server($server));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
# delete_servers_from_file(file, &servers...)
|
||||
# Deletes server blocks from one config file and removes the file if empty
|
||||
sub delete_servers_from_file
|
||||
{
|
||||
my ($file, @servers) = @_;
|
||||
return 0 if (!@servers);
|
||||
my $lref = &read_file_lines($file);
|
||||
foreach my $server (sort { $b->{'line'} <=> $a->{'line'} } @servers) {
|
||||
my $len = $server->{'eline'} - $server->{'line'} + 1;
|
||||
splice(@$lref, $server->{'line'}, $len);
|
||||
}
|
||||
my $empty = 1;
|
||||
foreach my $line (@$lref) {
|
||||
if ($line =~ /\S/) {
|
||||
$empty = 0;
|
||||
last;
|
||||
}
|
||||
}
|
||||
&flush_file_lines($file);
|
||||
if ($empty) {
|
||||
foreach my $link (&server_file_links($file)) {
|
||||
&unlink_logged($link);
|
||||
}
|
||||
&unlink_logged($file);
|
||||
}
|
||||
return scalar(@servers);
|
||||
}
|
||||
|
||||
# get_server_list_rows(&http)
|
||||
# Returns row hashes for the server blocks list, preserving sites-available order
|
||||
sub get_server_list_rows
|
||||
{
|
||||
my ($http) = @_;
|
||||
my @allservers = &find("server", $http);
|
||||
my @servers = grep { &can_edit_server($_) } @allservers;
|
||||
my $default_first = sub {
|
||||
return ( grep { &is_default_server_block($_->{'server'}) } @_ ),
|
||||
( grep { !&is_default_server_block($_->{'server'}) } @_ );
|
||||
};
|
||||
if (&can_manage_server_files()) {
|
||||
my @rows;
|
||||
my %active_by_file;
|
||||
foreach my $s (@servers) {
|
||||
my $file = &resolve_links($s->{'file'});
|
||||
$file ||= $s->{'file'};
|
||||
push(@{$active_by_file{$file}}, $s);
|
||||
}
|
||||
my %done_server;
|
||||
foreach my $file (&get_add_to_files()) {
|
||||
my @fileservers = @{$active_by_file{$file} || [ ]};
|
||||
my $active = @fileservers ? 1 : 0;
|
||||
if (!@fileservers) {
|
||||
@fileservers = grep { &can_edit_server($_) }
|
||||
&find_servers_in_file($file);
|
||||
}
|
||||
foreach my $s (@fileservers) {
|
||||
push(@rows, { 'server' => $s,
|
||||
'active' => $active,
|
||||
'file' => $file });
|
||||
$done_server{$s}++;
|
||||
}
|
||||
}
|
||||
foreach my $s (@servers) {
|
||||
next if ($done_server{$s});
|
||||
push(@rows, { 'server' => $s,
|
||||
'active' => 1,
|
||||
'file' => $s->{'file'} });
|
||||
}
|
||||
return &$default_first(@rows);
|
||||
}
|
||||
return &$default_first(
|
||||
map { { 'server' => $_, 'active' => 1, 'file' => $_->{'file'} } }
|
||||
@servers);
|
||||
}
|
||||
|
||||
# server_file_link(file)
|
||||
# Returns the enabled symlink path for a server file
|
||||
sub server_file_link
|
||||
{
|
||||
my ($file) = @_;
|
||||
return undef if (!&can_manage_server_files());
|
||||
my $short = $file;
|
||||
$short =~ s/^.*\///;
|
||||
return $config{'add_link'}."/".$short;
|
||||
}
|
||||
|
||||
# server_file_links(file)
|
||||
# Returns enabled symlinks for a server file
|
||||
sub server_file_links
|
||||
{
|
||||
my ($file) = @_;
|
||||
my @rv;
|
||||
return @rv if (!&can_manage_server_files());
|
||||
my $rfile = &resolve_links($file);
|
||||
$rfile ||= $file;
|
||||
opendir(LINKDIR, $config{'add_link'}) || return @rv;
|
||||
foreach my $f (readdir(LINKDIR)) {
|
||||
next if ($f eq "." || $f eq "..");
|
||||
my $link = $config{'add_link'}."/".$f;
|
||||
next if (!-l $link);
|
||||
my $rlink = &resolve_links($link);
|
||||
if ($rlink && $rlink eq $rfile) {
|
||||
push(@rv, $link);
|
||||
}
|
||||
}
|
||||
closedir(LINKDIR);
|
||||
return @rv;
|
||||
}
|
||||
|
||||
# server_file_enabled(file)
|
||||
# Returns 1 if a server file has an enabled symlink
|
||||
sub server_file_enabled
|
||||
{
|
||||
my ($file) = @_;
|
||||
return scalar(&server_file_links($file)) ? 1 : 0;
|
||||
}
|
||||
|
||||
# enable_server_file(file)
|
||||
# Enables a server file and rolls back if nginx -t fails
|
||||
sub enable_server_file
|
||||
{
|
||||
my ($file) = @_;
|
||||
my $rfile = &resolve_links($file);
|
||||
$rfile ||= $file;
|
||||
my $link = &server_file_link($rfile);
|
||||
$link || return $text{'enable_elinkdir'};
|
||||
return undef if (&server_file_enabled($rfile));
|
||||
if (-e $link || -l $link) {
|
||||
return &text('enable_elinkexists', "<tt>".&html_escape($link)."</tt>");
|
||||
}
|
||||
&symlink_logged($rfile, $link) ||
|
||||
return &text('enable_elink', "<tt>".&html_escape($link)."</tt>",
|
||||
"<tt>".&html_escape($!)."</tt>");
|
||||
my $err = &test_config();
|
||||
if ($err) {
|
||||
&unlink_logged($link);
|
||||
return &text('enable_etest', "<tt>".&html_escape($err)."</tt>");
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
# disable_server_file(file)
|
||||
# Disables a server file and rolls back if nginx -t fails
|
||||
sub disable_server_file
|
||||
{
|
||||
my ($file) = @_;
|
||||
my @links = &server_file_links($file);
|
||||
return undef if (!@links);
|
||||
my @restore = map { [ $_, readlink($_) ] } @links;
|
||||
my @removed;
|
||||
foreach my $link (@links) {
|
||||
if (!&unlink_logged($link)) {
|
||||
foreach my $r (@removed) {
|
||||
&symlink_logged($r->[1], $r->[0])
|
||||
if (defined($r->[1]) && !-e $r->[0] && !-l $r->[0]);
|
||||
}
|
||||
return &text('enable_eunlink',
|
||||
"<tt>".&html_escape($link)."</tt>",
|
||||
"<tt>".&html_escape($!)."</tt>");
|
||||
}
|
||||
my ($restore) = grep { $_->[0] eq $link } @restore;
|
||||
push(@removed, $restore) if ($restore);
|
||||
}
|
||||
my $err = &test_config();
|
||||
if ($err) {
|
||||
foreach my $r (@restore) {
|
||||
&symlink_logged($r->[1], $r->[0])
|
||||
if (defined($r->[1]) && !-e $r->[0] && !-l $r->[0]);
|
||||
}
|
||||
return &text('enable_etest', "<tt>".&html_escape($err)."</tt>");
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
# proxy_pass_value(&proxy_pass)
|
||||
# Returns the target URL from a proxy_pass directive
|
||||
sub proxy_pass_value
|
||||
{
|
||||
my ($pp) = @_;
|
||||
my @w = @{$pp->{'words'}};
|
||||
return (@w ? $w[0] : undef) || $pp->{'value'};
|
||||
}
|
||||
|
||||
# server_proxy_target(&server|&location)
|
||||
# Returns the first proxy_pass target under a server or location block
|
||||
sub server_proxy_target
|
||||
{
|
||||
my ($conf) = @_;
|
||||
my ($pp) = &find_recursive("proxy_pass", $conf);
|
||||
return undef if (!$pp);
|
||||
return &proxy_pass_value($pp);
|
||||
}
|
||||
|
||||
# server_proxy_pairs(&server)
|
||||
# Returns location path and proxy_pass target pairs for a server block
|
||||
sub server_proxy_pairs
|
||||
{
|
||||
my ($server) = @_;
|
||||
my @rv;
|
||||
foreach my $loc (&find("location", $server)) {
|
||||
my $path = &location_path($loc) || "/";
|
||||
foreach my $pp (&find_recursive("proxy_pass", $loc)) {
|
||||
my $target = &proxy_pass_value($pp);
|
||||
push(@rv, [ $path, $target ])
|
||||
if (defined($target) && $target ne "");
|
||||
}
|
||||
}
|
||||
foreach my $pp (&find("proxy_pass", $server)) {
|
||||
my $target = &proxy_pass_value($pp);
|
||||
push(@rv, [ "/", $target ])
|
||||
if (defined($target) && $target ne "");
|
||||
}
|
||||
return @rv;
|
||||
}
|
||||
|
||||
# server_root_summary(&server)
|
||||
# Returns the root directory for a server block, or a missing-root message
|
||||
sub server_root_summary
|
||||
{
|
||||
my ($server) = @_;
|
||||
my $root = &server_root_value($server);
|
||||
return defined($root) && $root ne "" ? &html_escape($root) :
|
||||
"<i>$text{'index_noroot'}</i>";
|
||||
}
|
||||
|
||||
# server_root_value(&server)
|
||||
# Returns the configured root directory for a server block
|
||||
sub server_root_value
|
||||
{
|
||||
my ($server) = @_;
|
||||
my $root = &find_value("root", $server);
|
||||
return $root if ($root);
|
||||
|
||||
my @locs = &find("location", $server);
|
||||
my ($rootloc) = grep { &location_path($_) eq '/' } @locs;
|
||||
if ($rootloc) {
|
||||
$root = &find_value("root", $rootloc);
|
||||
return $root if ($root);
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
# server_proxy_summary(&server)
|
||||
# Returns the most relevant proxy target for a server block
|
||||
sub server_proxy_summary
|
||||
{
|
||||
my ($server) = @_;
|
||||
my @pairs = &server_proxy_pairs($server);
|
||||
return "<i>$text{'index_noproxy'}</i>" if (!@pairs);
|
||||
return join("<br>", map {
|
||||
&html_escape($_->[0])." ⇾ ".&html_escape($_->[1])
|
||||
} @pairs);
|
||||
}
|
||||
|
||||
# server_root_proxy_summary(&server)
|
||||
# Returns the root directory or most relevant proxy target for a server block
|
||||
sub server_root_proxy_summary
|
||||
{
|
||||
my ($server) = @_;
|
||||
my $root = &server_root_value($server);
|
||||
return &html_escape($root) if (defined($root) && $root ne "");
|
||||
my $pp = &server_proxy_target($server);
|
||||
return &text('server_pp', "<tt>".&html_escape($pp)."</tt>")
|
||||
if ($pp);
|
||||
return &server_root_summary($server);
|
||||
}
|
||||
|
||||
# server_root_proxy_state(&server)
|
||||
# Returns booleans for whether a server has root and proxy_pass directives
|
||||
sub server_root_proxy_state
|
||||
{
|
||||
my ($server) = @_;
|
||||
my $has_root = &find_recursive("root", $server) ? 1 : 0;
|
||||
my $has_proxy = &server_proxy_target($server) ? 1 : 0;
|
||||
return ($has_root, $has_proxy);
|
||||
}
|
||||
|
||||
# server_url(&server)
|
||||
# Returns the browser URL for a server block
|
||||
sub server_url
|
||||
{
|
||||
my ($server) = @_;
|
||||
my $name = &find_value("server_name", $server);
|
||||
return undef if (&is_default_server_block($server));
|
||||
return undef if (!$name || $name !~ /^[A-Za-z0-9.-]+$/);
|
||||
|
||||
my ($best_scheme, $best_port);
|
||||
foreach my $l (&find("listen", $server)) {
|
||||
my @w = @{$l->{'words'}};
|
||||
my $addr = shift(@w);
|
||||
next if (!$addr);
|
||||
my (undef, $port) = &split_ip_port($addr);
|
||||
my $ssl = grep { $_ eq "ssl" } @w;
|
||||
my $scheme = $ssl || $port == 443 ? "https" : "http";
|
||||
if (!$best_scheme || $scheme eq "https") {
|
||||
($best_scheme, $best_port) = ($scheme, $port);
|
||||
}
|
||||
}
|
||||
$best_scheme ||= "http";
|
||||
$best_port ||= $best_scheme eq "https" ? 443 : 80;
|
||||
$best_port = undef if ($best_scheme eq "http" && $best_port == 80 ||
|
||||
$best_scheme eq "https" && $best_port == 443);
|
||||
return $best_scheme."://".$name.($best_port ? ":".$best_port : "")."/";
|
||||
}
|
||||
|
||||
# find_server(id)
|
||||
# Convenience function to find an HTTP server object with some ID
|
||||
sub find_server
|
||||
|
||||
345
nginx/t/server-files.t
Normal file
345
nginx/t/server-files.t
Normal file
@@ -0,0 +1,345 @@
|
||||
#!/usr/bin/perl
|
||||
# Tests for Debian-style Nginx sites-available/sites-enabled handling.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More;
|
||||
use File::Basename qw(dirname);
|
||||
use File::Path qw(make_path);
|
||||
use File::Spec;
|
||||
use File::Temp qw(tempdir);
|
||||
use Cwd qw(abs_path);
|
||||
|
||||
my $root = abs_path(File::Spec->catdir(dirname(__FILE__), '..', '..'));
|
||||
my $tmp = abs_path(tempdir(CLEANUP => 1));
|
||||
my $webmin_config = File::Spec->catdir($tmp, 'webmin-config');
|
||||
my $webmin_var = File::Spec->catdir($tmp, 'webmin-var');
|
||||
my $available = File::Spec->catdir($tmp, 'sites-available');
|
||||
my $enabled = File::Spec->catdir($tmp, 'sites-enabled');
|
||||
my $nginx_conf = File::Spec->catfile($tmp, 'nginx.conf');
|
||||
|
||||
make_path($webmin_config, $webmin_var, "$webmin_config/nginx",
|
||||
$available, $enabled);
|
||||
|
||||
sub write_text
|
||||
{
|
||||
my ($file, $text) = @_;
|
||||
open(my $fh, '>', $file) || die "Failed to write $file: $!";
|
||||
print $fh $text;
|
||||
close($fh) || die "Failed to close $file: $!";
|
||||
}
|
||||
|
||||
sub server_conf
|
||||
{
|
||||
my ($name, $body) = @_;
|
||||
return "server {\n".
|
||||
"\tserver_name $name;\n".
|
||||
"\tlisten 80;\n".
|
||||
$body.
|
||||
"}\n";
|
||||
}
|
||||
|
||||
my $alpha = File::Spec->catfile($available, 'alpha.conf');
|
||||
my $beta = File::Spec->catfile($available, 'beta.conf');
|
||||
my $charlie = File::Spec->catfile($available, 'charlie.conf');
|
||||
my $default = File::Spec->catfile($available, 'default');
|
||||
|
||||
write_text($alpha, server_conf('alpha.example', "\troot /srv/alpha;\n"));
|
||||
write_text($beta, server_conf('beta.example',
|
||||
"\tlocation / {\n".
|
||||
"\t\tproxy_pass http://127.0.0.1:8080;\n".
|
||||
"\t}\n"));
|
||||
write_text($charlie, server_conf('charlie.example', "\troot /srv/charlie;\n"));
|
||||
write_text($default, server_conf('_', "\troot /srv/default;\n"));
|
||||
write_text($nginx_conf,
|
||||
"events {\n".
|
||||
"}\n".
|
||||
"http {\n".
|
||||
"\tinclude $enabled/*;\n".
|
||||
"}\n");
|
||||
|
||||
symlink($alpha, File::Spec->catfile($enabled, 'alpha.conf')) ||
|
||||
die "Failed to symlink alpha: $!";
|
||||
symlink($charlie, File::Spec->catfile($enabled, 'charlie.conf')) ||
|
||||
die "Failed to symlink charlie: $!";
|
||||
symlink($default, File::Spec->catfile($enabled, 'default')) ||
|
||||
die "Failed to symlink default: $!";
|
||||
|
||||
write_text(File::Spec->catfile($webmin_config, 'config'),
|
||||
"os_type=unix\n".
|
||||
"os_version=1\n".
|
||||
"real_os_type=Unix\n".
|
||||
"real_os_version=1\n");
|
||||
write_text(File::Spec->catfile($webmin_config, 'miniserv.conf'),
|
||||
"root=$root\n");
|
||||
write_text(File::Spec->catfile($webmin_config, 'nginx', 'config'),
|
||||
"nginx_config=$nginx_conf\n".
|
||||
"nginx_cmd=/bin/true\n".
|
||||
"add_to=$available\n".
|
||||
"add_link=$enabled\n");
|
||||
|
||||
$ENV{'WEBMIN_CONFIG'} = $webmin_config;
|
||||
$ENV{'WEBMIN_VAR'} = $webmin_var;
|
||||
$ENV{'FOREIGN_MODULE_NAME'} = 'nginx';
|
||||
$ENV{'FOREIGN_ROOT_DIRECTORY'} = $root;
|
||||
$ENV{'REMOTE_USER'} = 'root';
|
||||
|
||||
unshift(@INC, $root);
|
||||
require File::Spec->catfile($root, 'nginx', 'nginx-lib.pl');
|
||||
|
||||
{
|
||||
no warnings 'once';
|
||||
$main::text{'server_pp'} = 'Proxy to $1';
|
||||
$main::text{'index_noroot'} = 'No root directory';
|
||||
$main::text{'index_noproxy'} = 'No proxy target';
|
||||
}
|
||||
|
||||
sub http_config
|
||||
{
|
||||
main::flush_config_cache();
|
||||
my $http = main::find('http', main::get_config());
|
||||
ok($http, 'test nginx config has an http block');
|
||||
return $http;
|
||||
}
|
||||
|
||||
sub row_names
|
||||
{
|
||||
return [ map { scalar main::find_value('server_name', $_->{'server'}) } @_ ];
|
||||
}
|
||||
|
||||
sub row_states
|
||||
{
|
||||
return [ map { $_->{'active'} ? 'enabled' : 'disabled' } @_ ];
|
||||
}
|
||||
|
||||
subtest 'sites-available files are manageable and ordered' => sub {
|
||||
ok(main::can_manage_server_files(), 'sites-available/enabled dirs are manageable');
|
||||
is_deeply(
|
||||
[ main::get_add_to_files() ],
|
||||
[ $alpha, $beta, $charlie, $default ],
|
||||
'available files are listed in stable filename order',
|
||||
);
|
||||
|
||||
my @rows = main::get_server_list_rows(http_config());
|
||||
is_deeply(row_names(@rows),
|
||||
[ '_', 'alpha.example', 'beta.example', 'charlie.example' ],
|
||||
'default site is first and other sites stay in sites-available order');
|
||||
is_deeply(row_states(@rows),
|
||||
[ 'enabled', 'enabled', 'disabled', 'enabled' ],
|
||||
'row active state follows sites-enabled symlinks');
|
||||
};
|
||||
|
||||
subtest 'disable removes only the enabled symlink' => sub {
|
||||
{
|
||||
no warnings 'redefine';
|
||||
local *main::test_config = sub { return undef; };
|
||||
is(main::disable_server_file($alpha), undef, 'disable succeeds');
|
||||
}
|
||||
|
||||
ok(-f $alpha, 'disable leaves the sites-available file in place');
|
||||
ok(!-e File::Spec->catfile($enabled, 'alpha.conf'),
|
||||
'disable removes the sites-enabled symlink');
|
||||
|
||||
my @rows = main::get_server_list_rows(http_config());
|
||||
is_deeply(row_names(@rows),
|
||||
[ '_', 'alpha.example', 'beta.example', 'charlie.example' ],
|
||||
'disabled row remains in the same list position');
|
||||
is_deeply(row_states(@rows),
|
||||
[ 'enabled', 'disabled', 'disabled', 'enabled' ],
|
||||
'disabled row status is updated');
|
||||
};
|
||||
|
||||
subtest 'enable creates a symlink without touching the source file' => sub {
|
||||
{
|
||||
no warnings 'redefine';
|
||||
local *main::test_config = sub { return undef; };
|
||||
is(main::enable_server_file($beta), undef, 'enable succeeds');
|
||||
}
|
||||
|
||||
my $link = File::Spec->catfile($enabled, 'beta.conf');
|
||||
ok(-f $beta, 'enable leaves the sites-available file in place');
|
||||
ok(-l $link, 'enable creates the sites-enabled symlink');
|
||||
is(readlink($link), $beta, 'enabled symlink points to the available file');
|
||||
ok(main::server_file_enabled($beta), 'server_file_enabled sees the symlink');
|
||||
};
|
||||
|
||||
subtest 'legacy create/delete link helpers still manage symlinks' => sub {
|
||||
my $echo = File::Spec->catfile($available, 'echo.conf');
|
||||
my $echo_link = File::Spec->catfile($enabled, 'echo.conf');
|
||||
write_text($echo, server_conf('echo.example', "\troot /srv/echo;\n"));
|
||||
my $server = { 'file' => $echo };
|
||||
|
||||
main::create_server_link($server);
|
||||
ok(-l $echo_link, 'create_server_link creates expected symlink');
|
||||
is(readlink($echo_link), $echo, 'created symlink points to server file');
|
||||
|
||||
main::delete_server_link($server);
|
||||
ok(!-e $echo_link, 'delete_server_link removes expected symlink');
|
||||
ok(-f $echo, 'delete_server_link leaves server file in place');
|
||||
};
|
||||
|
||||
subtest 'disabled server blocks can be deleted from available files' => sub {
|
||||
my $multi = File::Spec->catfile($available, 'multi.conf');
|
||||
write_text($multi,
|
||||
server_conf('one.example', "\troot /srv/one;\n").
|
||||
server_conf('two.example', "\troot /srv/two;\n"));
|
||||
my ($one_server) = grep {
|
||||
main::find_value('server_name', $_) eq 'one.example'
|
||||
} main::find_servers_in_file($multi);
|
||||
|
||||
is(main::delete_servers_from_file($multi, $one_server), 1,
|
||||
'delete_servers_from_file removes one disabled server block');
|
||||
ok(-f $multi, 'file remains when another server block is present');
|
||||
is_deeply(
|
||||
[ map { scalar main::find_value('server_name', $_) }
|
||||
main::find_servers_in_file($multi) ],
|
||||
[ 'two.example' ],
|
||||
'only the unselected disabled server block remains');
|
||||
|
||||
my ($two_server) = main::find_servers_in_file($multi);
|
||||
is(main::delete_servers_from_file($multi, $two_server), 1,
|
||||
'delete_servers_from_file removes the last disabled server block');
|
||||
ok(!-e $multi, 'empty available file is removed after last block delete');
|
||||
};
|
||||
|
||||
subtest 'same-name symlink to another target is not disabled' => sub {
|
||||
my $otherdir = File::Spec->catdir($tmp, 'other-sites');
|
||||
my $other = File::Spec->catfile($otherdir, 'charlie.conf');
|
||||
my $link = File::Spec->catfile($enabled, 'charlie.conf');
|
||||
make_path($otherdir);
|
||||
write_text($other, server_conf('other.example', "\troot /srv/other;\n"));
|
||||
unlink($link) || die "Failed to remove charlie link: $!";
|
||||
symlink($other, $link) || die "Failed to symlink other charlie: $!";
|
||||
|
||||
ok(!main::server_file_enabled($charlie),
|
||||
'same-name symlink to another file is not considered enabled');
|
||||
{
|
||||
no warnings 'redefine';
|
||||
local *main::test_config = sub { return undef; };
|
||||
is(main::disable_server_file($charlie), undef, 'disable is a no-op');
|
||||
}
|
||||
ok(-l $link, 'same-name symlink to another target is preserved');
|
||||
is(readlink($link), $other, 'preserved symlink target is unchanged');
|
||||
};
|
||||
|
||||
subtest 'file-level actions require access to every server in the file' => sub {
|
||||
my $mixed = File::Spec->catfile($available, 'mixed.conf');
|
||||
write_text($mixed,
|
||||
server_conf('alpha.example', "\troot /srv/mixed-alpha;\n").
|
||||
server_conf('hidden.example', "\troot /srv/mixed-hidden;\n"));
|
||||
|
||||
{
|
||||
no warnings 'once';
|
||||
local $main::access{'vhosts'} = 'alpha.example';
|
||||
ok(!main::can_manage_server_file($mixed),
|
||||
'mixed-access file cannot be managed by a restricted user');
|
||||
}
|
||||
ok(main::can_manage_server_file($mixed),
|
||||
'mixed-access file can be managed when vhost access is unrestricted');
|
||||
};
|
||||
|
||||
subtest 'nginx -t failure rolls back link changes' => sub {
|
||||
my $delta = File::Spec->catfile($available, 'delta.conf');
|
||||
my $delta_link = File::Spec->catfile($enabled, 'delta.conf');
|
||||
write_text($delta, server_conf('delta.example', "\troot /srv/delta;\n"));
|
||||
|
||||
{
|
||||
no warnings 'redefine';
|
||||
local *main::test_config = sub { return 'bad config'; };
|
||||
like(main::enable_server_file($delta), qr/bad config/,
|
||||
'failed enable reports nginx -t output');
|
||||
}
|
||||
ok(!-e $delta_link, 'failed enable removes the new symlink');
|
||||
|
||||
symlink($delta, $delta_link) || die "Failed to symlink delta: $!";
|
||||
{
|
||||
no warnings 'redefine';
|
||||
local *main::test_config = sub { return 'bad config'; };
|
||||
like(main::disable_server_file($delta), qr/bad config/,
|
||||
'failed disable reports nginx -t output');
|
||||
}
|
||||
ok(-l $delta_link, 'failed disable restores the removed symlink');
|
||||
is(readlink($delta_link), $delta, 'restored symlink target is unchanged');
|
||||
};
|
||||
|
||||
subtest 'root and proxy summaries are detected' => sub {
|
||||
my ($alpha_server) = main::find_servers_in_file($alpha);
|
||||
my ($beta_server) = main::find_servers_in_file($beta);
|
||||
my ($default_server) = main::find_servers_in_file($default);
|
||||
my $path_proxy = File::Spec->catfile($available, 'path-proxy.conf');
|
||||
write_text($path_proxy,
|
||||
"server {\n".
|
||||
"\tserver_name path.example;\n".
|
||||
"\tlisten 443 ssl http2;\n".
|
||||
"\tlocation /webmin {\n".
|
||||
"\t\tproxy_pass https://127.0.0.1:10000/;\n".
|
||||
"\t\tproxy_http_version 1.1;\n".
|
||||
"\t}\n".
|
||||
"}\n");
|
||||
my $named = File::Spec->catfile($available, 'named-proxy.conf');
|
||||
write_text($named,
|
||||
"server {\n".
|
||||
"\tserver_name named.example;\n".
|
||||
"\tlisten 80;\n".
|
||||
"\tlocation / {\n".
|
||||
"\t\ttry_files \$uri \@backend;\n".
|
||||
"\t}\n".
|
||||
"\tlocation \@backend {\n".
|
||||
"\t\tproxy_pass http://127.0.0.1:8081;\n".
|
||||
"\t}\n".
|
||||
"}\n");
|
||||
my ($path_proxy_server) = main::find_servers_in_file($path_proxy);
|
||||
my ($named_server) = main::find_servers_in_file($named);
|
||||
|
||||
is_deeply([ main::server_root_proxy_state($alpha_server) ], [ 1, 0 ],
|
||||
'root-only server state is detected');
|
||||
is(main::server_root_summary($alpha_server), '/srv/alpha',
|
||||
'root-only server root column shows the root directory');
|
||||
is(main::server_proxy_summary($alpha_server), '<i>No proxy target</i>',
|
||||
'root-only server proxy column shows a missing-proxy message');
|
||||
is(main::server_root_proxy_summary($alpha_server), '/srv/alpha',
|
||||
'root-only summary shows the root directory');
|
||||
is(main::server_url($alpha_server), 'http://alpha.example/',
|
||||
'root-only server URL uses HTTP default port');
|
||||
is(main::server_url($default_server), undef,
|
||||
'default server has no URL link target');
|
||||
|
||||
is_deeply([ main::server_root_proxy_state($beta_server) ], [ 0, 1 ],
|
||||
'proxy-only server state is detected');
|
||||
is(main::server_root_summary($beta_server), '<i>No root directory</i>',
|
||||
'proxy-only server root column shows a missing-root message');
|
||||
like(main::server_proxy_summary($beta_server),
|
||||
qr{/ ⇾ http://127\.0\.0\.1:8080},
|
||||
'proxy-only server proxy column shows the path and proxy target');
|
||||
like(main::server_root_proxy_summary($beta_server),
|
||||
qr{http://127\.0\.0\.1:8080},
|
||||
'proxy-only summary shows the proxy target');
|
||||
is(main::server_url($beta_server), 'http://beta.example/',
|
||||
'proxy-only server URL uses HTTP default port');
|
||||
|
||||
is_deeply([ main::server_root_proxy_state($path_proxy_server) ], [ 0, 1 ],
|
||||
'non-root-location proxy state is detected');
|
||||
is(main::server_root_summary($path_proxy_server), '<i>No root directory</i>',
|
||||
'non-root-location proxy root column shows a missing-root message');
|
||||
like(main::server_proxy_summary($path_proxy_server),
|
||||
qr{/webmin ⇾ https://127\.0\.0\.1:10000/},
|
||||
'non-root-location proxy column shows the path and proxy target');
|
||||
like(main::server_root_proxy_summary($path_proxy_server),
|
||||
qr{https://127\.0\.0\.1:10000/},
|
||||
'non-root-location proxy summary shows the proxy target');
|
||||
is(main::server_url($path_proxy_server), 'https://path.example/',
|
||||
'SSL listener URL uses HTTPS default port');
|
||||
|
||||
is_deeply([ main::server_root_proxy_state($named_server) ], [ 0, 1 ],
|
||||
'named-location proxy state is detected');
|
||||
like(main::server_proxy_summary($named_server),
|
||||
qr{\@backend ⇾ http://127\.0\.0\.1:8081},
|
||||
'named-location proxy column shows the path and proxy target');
|
||||
like(main::server_root_proxy_summary($named_server),
|
||||
qr{http://127\.0\.0\.1:8081},
|
||||
'named-location proxy summary shows the proxy target');
|
||||
is(main::server_url($named_server), 'http://named.example/',
|
||||
'named-location proxy URL uses HTTP default port');
|
||||
};
|
||||
|
||||
done_testing();
|
||||
Reference in New Issue
Block a user