aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/haproxy-devel/haproxy.inc50
-rw-r--r--config/haproxy-devel/haproxy.xml5
-rw-r--r--config/haproxy-devel/haproxy_files.php176
-rw-r--r--config/haproxy-devel/haproxy_htmllist.inc50
-rw-r--r--config/haproxy-devel/haproxy_listeners_edit.php5
-rw-r--r--config/haproxy-devel/haproxy_pool_edit.php40
-rw-r--r--config/haproxy-devel/pkg_haproxy_tabs.inc2
7 files changed, 319 insertions, 9 deletions
diff --git a/config/haproxy-devel/haproxy.inc b/config/haproxy-devel/haproxy.inc
index 5b56595a..c839cd4c 100644
--- a/config/haproxy-devel/haproxy.inc
+++ b/config/haproxy-devel/haproxy.inc
@@ -196,6 +196,19 @@ $a_sticky_type['stick_rdp_cookie'] = array('name' => 'Stick on RDP-cookie',
'descr' => "Uses a RDP-Cookie send by the mstsc client, note that not all clients send this.",
'cookiedescr' => 'EXAMPLE: msts or mstshash');
+
+global $a_error;
+$a_error = array();
+$a_error['200'] = array('descr' => "stats or monitoring requests");
+$a_error['400'] = array('descr' => "request invalid or too large");
+$a_error['401'] = array('descr' => "authentication is required to perform the action");
+$a_error['403'] = array('descr' => "request is forbidden");
+$a_error['408'] = array('descr' => "timeout before the request is complete");
+$a_error['500'] = array('descr' => "internal error");
+$a_error['502'] = array('descr' => "server response invalid or blocked");
+$a_error['503'] = array('descr' => "no server was available to handle the request");
+$a_error['504'] = array('descr' => "timeout before the server responds");
+
if(!function_exists('group_ports')){
// function group_ports() is present in pfSense 2.2 in util.inc
/* create ranges of sequential port numbers (200:215) and remove duplicates */
@@ -308,6 +321,20 @@ function haproxy_hostoralias_to_list($host_or_alias) {
return $result;
}
+function haproxy_get_fileslist() {
+ // returns the files array with 'keys'.
+ $result = array();
+ global $config;
+ // create a copy to not modify the original 'keyless' array
+ $a_files = $config['installedpackages']['haproxy']['files']['item'];
+ if (!is_array($a_files)) $a_files = array();
+ foreach($a_files as $file) {
+ $key = $file['name'];
+ $result[$key] = $file;
+ }
+ return $result;
+}
+
function haproxy_custom_php_deinstall_command() {
global $static_output;
$static_output .= "HAProxy, running haproxy_custom_php_deinstall_command()\n";
@@ -603,7 +630,7 @@ function haproxy_find_acl($name) {
function write_backend($configpath, $fd, $name, $pool, $frontend) {
if(!is_array($pool['ha_servers']['item']) && !$pool['stats_enabled']=='yes')
return;
- global $a_checktypes, $a_cookiemode;
+ global $a_checktypes, $a_cookiemode, $a_files, $a_error;
$a_servers = &$pool['ha_servers']['item'];
$frontendtype = $frontend['type'];
@@ -667,6 +694,23 @@ function write_backend($configpath, $fd, $name, $pool, $frontend) {
fwrite ($fd, "\tstats\t\t\tscope " . $scope_item . "\n");
}
}
+
+ if (is_arrayset($pool,'errorfiles','item')) {
+ foreach($pool['errorfiles']['item'] as $errorfile) {
+ if (!is_array($a_files))// load only once
+ $a_files = haproxy_get_fileslist();
+ $file = $errorfile['errorfile'];
+ $errorcodes = explode(",",$errorfile['errorcode']);
+ foreach($errorcodes as $errorcode) {
+ $filename = "$configpath/errorfile_{$name}_{$errorcode}_{$file}";
+ $content = base64_decode($a_files[$file]['content']);
+ $content = str_replace('{errormsg}', $a_error[$errorcode]['descr'], $content);
+ $content = str_replace('{errorcode}', $errorcode, $content);
+ file_put_contents($filename, $content);
+ fwrite ($fd, "\terrorfile\t\t\t" . $errorcode ." " . $filename . "\n");
+ }
+ }
+ }
}
switch($pool["persist_sticky_type"]) {
@@ -1668,7 +1712,7 @@ function get_frontend_ipport($frontend, $userfriendly=false) {
$mainfrontend = get_primaryfrontend($frontend);
$newline = "";
$result = array();
- if (!isset($mainfrontend))
+ if (!is_arrayset($mainfrontend,"a_extaddr","item"))
return $result;
foreach($mainfrontend['a_extaddr']['item'] as $extaddr) {
if ($extaddr['extaddr'] == 'custom'){
@@ -1725,6 +1769,8 @@ function get_haproxy_frontends($excludeitem="") {
global $config;
$a_frontend = &$config['installedpackages']['haproxy']['ha_backends']['item'];
$result = array();
+ if(!is_array($a_frontend))
+ return $result;
foreach($a_frontend as &$frontend)
{
if ($frontend['secondary'])
diff --git a/config/haproxy-devel/haproxy.xml b/config/haproxy-devel/haproxy.xml
index acd934a7..6156c174 100644
--- a/config/haproxy-devel/haproxy.xml
+++ b/config/haproxy-devel/haproxy.xml
@@ -90,6 +90,11 @@
<additional_files_needed>
<prefix>/usr/local/www/</prefix>
<chmod>077</chmod>
+ <item>https://packages.pfsense.org/packages/config/haproxy-devel/haproxy_files.php</item>
+ </additional_files_needed>
+ <additional_files_needed>
+ <prefix>/usr/local/www/</prefix>
+ <chmod>077</chmod>
<item>https://packages.pfsense.org/packages/config/haproxy-devel/haproxy_pools.php</item>
</additional_files_needed>
<additional_files_needed>
diff --git a/config/haproxy-devel/haproxy_files.php b/config/haproxy-devel/haproxy_files.php
new file mode 100644
index 00000000..4946a7be
--- /dev/null
+++ b/config/haproxy-devel/haproxy_files.php
@@ -0,0 +1,176 @@
+<?php
+/* $Id: load_balancer_virtual_server.php,v 1.6.2.1 2006/01/02 23:46:24 sullrich Exp $ */
+/*
+ haproxy_pools.php
+ part of pfSense (https://www.pfsense.org/)
+ Copyright (C) 2014 PiBa-NL
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+$shortcut_section = "haproxy";
+require_once("guiconfig.inc");
+require_once("haproxy.inc");
+require_once("pkg_haproxy_tabs.inc");
+require_once("haproxy_htmllist.inc");
+
+$a_files = &$config['installedpackages']['haproxy']['files']['item'];
+if (!is_array($a_files)) $a_files = array();
+$a_pools = &$config['installedpackages']['haproxy']['ha_pools']['item'];
+if (!is_array($a_pools)) $a_pools = array();
+
+
+$fields_files = array();
+$fields_files[0]['name']="name";
+$fields_files[0]['columnheader']="Name";
+$fields_files[0]['colwidth']="30%";
+$fields_files[0]['type']="textbox";
+$fields_files[0]['size']="20";
+
+$fields_files[1]['name']="content";
+$fields_files[1]['columnheader']="content";
+$fields_files[1]['colwidth']="70%";
+$fields_files[1]['type']="textarea";
+$fields_files[1]['size']="70";
+
+$fileslist = new HaproxyHtmlList("table_files", $fields_files);
+$fileslist->keyfield = "name";
+
+if ($_POST) {
+ $pconfig = $_POST;
+
+ if ($_POST['apply']) {
+ $result = haproxy_check_and_run($savemsg, true);
+ if ($result)
+ unlink_if_exists($d_haproxyconfdirty_path);
+ } else {
+ $a_files = $fileslist->haproxy_htmllist_get_values($fields_files);
+ $filedupcheck = array();
+
+ foreach($a_files as $key => $file) {
+ $name = $file['name'];
+ if (!preg_match("/^[a-zA-Z][a-zA-Z0-9\.\-_]*$/", $file['name']))
+ $input_errors[] = "The field 'Name' (".htmlspecialchars($file['name']).") contains invalid characters. Use only: a-zA-Z0-9.-_ and start with a letter";
+ if (isset($filedupcheck[$name]))
+ $input_errors[] = "Duplicate names are not allowed: " . htmlspecialchars($name);
+ $filedupcheck[$name] = true;
+ }
+
+ // replace references in backends to renamed 'files'
+ foreach($a_pools as &$backend) {
+ if (is_arrayset($backend,'errorfiles','item'))
+ foreach($backend['errorfiles']['item'] as &$errorfile) {
+ $found = false;
+ foreach($a_files as $key => $file) {
+ if ($errorfile['errorfile'] == $key) {
+ $errorfile['errorfile'] = $file['name'];
+ $found = true;
+ }
+ }
+ if (!$found)
+ $input_errors[] = "Errorfile marked for deletion: " . $errorfile['errorfile'] . " which is used in backend " . $backend['name'];
+ }
+ }
+ if (!$input_errors) {
+ // save config when no errors found
+ touch($d_haproxyconfdirty_path);
+ write_config($changedesc);
+ header("Location: haproxy_files.php");
+ exit;
+ }
+ }
+}
+
+$pf_version=substr(trim(file_get_contents("/etc/version")),0,3);
+
+$pgtitle = "Services: HAProxy: Files";
+include("head.inc");
+
+?>
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+<?php include("fbegin.inc"); ?>
+<form action="haproxy_files.php" method="post">
+<?php if ($input_errors) print_input_errors($input_errors); ?>
+<?php if ($savemsg) print_info_box($savemsg); ?>
+<?php if (file_exists($d_haproxyconfdirty_path)): ?>
+<?php print_info_box_np("The haproxy configuration has been changed.<br/>You must apply the changes in order for them to take effect.");?><br/>
+<?php endif; ?>
+<table width="100%" border="0" cellpadding="0" cellspacing="0">
+ <tr><td class="tabnavtbl">
+ <?php
+ haproxy_display_top_tabs_active($haproxy_tab_array['haproxy'], "files");
+ ?>
+ </td></tr>
+ <tr>
+ <td>
+ <div id="mainarea">
+ <table class="tabcont" width="100%" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td>
+ Files can be used for errorfiles, that can return custom error pages in
+ case haproxy reports a error (like no available backend). The content needs
+ to be less than the buffer size which is typically 8kb.
+ There are 2 possible variables to use inside the template:
+ Put these variables in the content of the errorfile templates and they will be replaced by the actual errorcode / message. (include the curly braces around the text)<br/>
+ <b>{errorcode}</b> this represents the errorcode<br/>
+ <b>{errormsg}</b> this represents the human readable error<br/>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ &nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <?
+ $counter=0;
+ $fileslist->Draw($a_files);
+ ?>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ &nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td width="78%">
+ <input name="Submit" type="submit" class="formbtn" value="Save" onClick="enable_change(true)" />
+ </td>
+ </tr>
+ </table>
+ </div>
+ </table>
+ </form>
+<script type="text/javascript">
+ totalrows = <?php echo $counter; ?>;
+<?
+ phparray_to_javascriptarray($fields_files,"fields_files",Array('/*','/*/name','/*/type','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name'));
+?>
+</script>
+
+<?php
+haproxy_htmllist_js();
+include("fend.inc"); ?>
+</body>
+</html>
diff --git a/config/haproxy-devel/haproxy_htmllist.inc b/config/haproxy-devel/haproxy_htmllist.inc
index 98f7ab94..f873028e 100644
--- a/config/haproxy-devel/haproxy_htmllist.inc
+++ b/config/haproxy-devel/haproxy_htmllist.inc
@@ -46,6 +46,7 @@ class HaproxyHtmlList
private $fields = array();
public $editmode = false;
public $fields_details = null;
+ public $keyfield = "";
public function HaproxyHtmlList($tablename, $fields){
$this->tablename = $tablename;
@@ -64,10 +65,25 @@ class HaproxyHtmlList
foreach($this->fields as $item){
$itemname = $item['name'];
$value[$itemname] = $_POST[$itemname.$x];
+ if ($item['type'] == 'textarea')
+ $value[$itemname] = base64_encode($value[$itemname]);
$add_item |= isset($_POST[$itemname.$x]);
}
- if ($add_item)
- $values[] = $value;
+ if ($add_item) {
+ if ($this->keyfield != "") {
+ if (isset($_POST[$this->tablename."_key".$x]))
+ $key = $_POST[$this->tablename."_key".$x];
+ else
+ $key = $_POST[$this->keyfield.$x];
+
+ } else
+ $key = "";
+
+ if (isset($values[$key]))
+ $values[] = $value;
+ else
+ $values[$key] = $value;
+ }
}
return $values;
}
@@ -78,13 +94,17 @@ class HaproxyHtmlList
if ($editable) {
$itemtype = $item['type'];
if ($itemtype == "select"){
- //updatevisibility()
echo_html_select($itemnamenr, $item['items'], $itemvalue,"","html_listitem_change(\"{$this->tablename}\",\"{$itemname}\",\"{$counter}\",this);", "width:{$item['size']}");
} else
if ($itemtype == "checkbox"){
$checked = $itemvalue=='yes' ? " checked" : "";
echo "<input onclick='html_listitem_change(\"{$this->tablename}\",\"{$itemname}\",\"{$counter}\",this);' name='$itemnamenr' id='$itemnamenr' type='checkbox'$checked value='yes' size='{$item['size']}' />";
} else
+ if ($itemtype == "textarea"){
+ echo "<textarea name='$itemnamenr' id='$itemnamenr' type='text' cols='{$item['size']}' rows='10'>";
+ echo htmlspecialchars(base64_decode($itemvalue));
+ echo "</textarea>";
+ } else
echo "<input name='$itemnamenr' id='$itemnamenr' type='text' value='{$itemvalue}' size='{$item['size']}' />";
} else {
if ($itemtype == "select"){
@@ -93,7 +113,10 @@ class HaproxyHtmlList
if ($itemtype == "checkbox"){
echo $itemvalue=='yes' ? gettext('yes') : gettext('no');
} else
- echo $itemvalue;
+ if ($itemtype == "textarea"){
+ echo htmlspecialchars(base64_decode($itemvalue));
+ } else
+ echo htmlspecialchars($itemvalue);
}
}
@@ -108,7 +131,16 @@ class HaproxyHtmlList
echo "<td width='5%' class=''></td>
</tr>";
if (is_array($rowvalues)){
- foreach($rowvalues as $value){
+ foreach($rowvalues as $keyid => $value){
+ if ($this->keyfield != "") {
+ if (preg_match("/[^0-9]/", $keyid))
+ $itemvalue = $keyid;
+ else
+ $itemvalue = $value[$this->keyfield];
+ $key = "<input name='{$tablename}_key{$counter}' id='{$tablename}_key{$counter}' type='hidden' value='{$itemvalue}'>";
+ } else
+ $key = "";
+
if (!$editstate) {
echo "<tr id='tr_view_$counter' ondblclick='editRow($counter); return false;' >";
$leftitem = true;
@@ -123,6 +155,7 @@ class HaproxyHtmlList
$this->haproxy_htmllist_drawcell($item, $itemvalue, false, $itemname, $counter);
echo "</td>";
$leftitem = false;
+
}
echo "
<td class='list'>
@@ -144,12 +177,13 @@ class HaproxyHtmlList
foreach($items as $item){
$itemname = $item['name'];
$itemvalue = $value[$itemname];
- echo "<td class='vtable'>";
+ echo "<td class='vtable'>".$key;
if (isset($item['customdrawcell'])) {
$item['customdrawcell']($item, $itemvalue, true, $item['name'].$counter);
} else
$this->haproxy_htmllist_drawcell($item, $itemvalue, true, $itemname, $counter);
echo "</td>";
+ $key = "";
}
echo "
<td class='list'>
@@ -288,6 +322,10 @@ function haproxy_htmllist_js(){
td.innerHTML="<input size='" + items[i]['size'] + "' name='" + items[i]['name'] + totalrows +
"' id='" + items[i]['name'] + totalrows +
"'><\/input> ";
+ } else if(items[i]['type'] == 'textarea') {
+ td.innerHTML="<textarea cols='" + items[i]['size'] + "' rows='30' name='" + items[i]['name'] + totalrows +
+ "' id='" + items[i]['name'] + totalrows +
+ "'><\/textarea> ";
} else if(items[i]['type'] == 'select') {
seltext = htmllist_get_select_options(tableId, items[i]['name']);
td.innerHTML="<select style='width:" + items[i]['size'] + "' name='" + items[i]['name'] + totalrows +
diff --git a/config/haproxy-devel/haproxy_listeners_edit.php b/config/haproxy-devel/haproxy_listeners_edit.php
index bfc39f87..a818fcfb 100644
--- a/config/haproxy-devel/haproxy_listeners_edit.php
+++ b/config/haproxy-devel/haproxy_listeners_edit.php
@@ -63,6 +63,8 @@ if (!is_array($config['installedpackages']['haproxy']['ha_backends']['item'])) {
$a_backend = &$config['installedpackages']['haproxy']['ha_backends']['item'];
$a_pools = &$config['installedpackages']['haproxy']['ha_pools']['item'];
+if (!is_array($a_pools))
+ $a_pools = array();
uasort($a_pools, haproxy_compareByName);
global $simplefields;
@@ -772,7 +774,8 @@ $primaryfrontends = get_haproxy_frontends($excludefrontend);
</td>
</tr>
<tr class="haproxy_ssloffloading_enabled haproxy_primary">
- <td class="vncell" colspan="2"><b>Client certificate verification options, leave this empty if you do want to ask for a client certificate</b></td>
+ <td class="vncell" colspan="2"><b>Client certificate verification options, leave this empty if you do not want to ask for a client certificate</b><br/>
+ The users that visit this site will need to load the client cert signed by the ca's listed below imported into their browser.</td>
</tr>
<tr class="haproxy_ssloffloading_enabled haproxy_primary">
<td width="22%" valign="top" class="vncell">Client verification CA certificates</td>
diff --git a/config/haproxy-devel/haproxy_pool_edit.php b/config/haproxy-devel/haproxy_pool_edit.php
index 30079847..5c7f66b9 100644
--- a/config/haproxy-devel/haproxy_pool_edit.php
+++ b/config/haproxy-devel/haproxy_pool_edit.php
@@ -42,6 +42,8 @@ if (!is_array($config['installedpackages']['haproxy']['ha_pools']['item'])) {
$a_pools = &$config['installedpackages']['haproxy']['ha_pools']['item'];
+$a_files = haproxy_get_fileslist();
+
if (isset($_POST['id']))
$id = $_POST['id'];
else
@@ -172,6 +174,19 @@ $fields_servers_details[7]['colwidth']="15%";
$fields_servers_details[7]['type']="textbox";
$fields_servers_details[7]['size']="80";
+$fields_errorfile = array();
+$fields_errorfile[0]['name']="errorcode";
+$fields_errorfile[0]['columnheader']="errorcode(s)";
+$fields_errorfile[0]['colwidth']="15%";
+$fields_errorfile[0]['type']="textbox";
+$fields_errorfile[0]['size']="70px";
+$fields_errorfile[1]['name']="errorfile";
+$fields_errorfile[1]['columnheader']="Error Page";
+$fields_errorfile[1]['colwidth']="30%";
+$fields_errorfile[1]['type']="select";
+$fields_errorfile[1]['size']="170px";
+$fields_errorfile[1]['items']=&$a_files;
+
if (isset($id) && $a_pools[$id]) {
$pconfig['advanced'] = base64_decode($a_pools[$id]['advanced']);
$pconfig['advanced_backend'] = base64_decode($a_pools[$id]['advanced_backend']);
@@ -179,6 +194,9 @@ if (isset($id) && $a_pools[$id]) {
foreach($simplefields as $stat)
$pconfig[$stat] = $a_pools[$id][$stat];
+
+ $a_errorfiles = &$a_pools[$id]['errorfiles']['item'];
+ if (!is_array($a_errorfiles)) $a_errorfiles = array();
}
if (isset($_GET['dup']))
@@ -269,6 +287,8 @@ if ($_POST) {
$input_errors[] = "The field 'Port' value is not a number.";
}
+ $a_errorfiles = haproxy_htmllist_get_values($fields_errorfile);
+
if ($_POST['strict_transport_security'] !== "" && !is_numeric($_POST['strict_transport_security']))
$input_errors[] = "The field 'Strict-Transport-Security' is not empty or a number.";
@@ -356,6 +376,9 @@ foreach($simplefields as $field){
if (fieldname == 'forwardto')
return "<?=haproxy_js_select_options($primaryfrontends);?>";
else
+ if (fieldname == 'errorfile')
+ return "<?=haproxy_js_select_options($a_files);?>";
+ else
return "<?=haproxy_js_select_options($a_servermodes);?>";
}
@@ -920,6 +943,21 @@ set by the 'retries' parameter.</div>
</tr>
<tr><td>&nbsp;</td></tr>
<tr>
+ <td colspan="2" valign="top" class="listtopic">Error files</td>
+ </tr>
+ <tr class="" align="left" id='errorfiles'>
+ <td colspan="2" valign="top" class="vtable">
+ Use these to replace the error pages that haproxy can generate by custom pages created on the files tab.
+ For example haproxy will generate a 503 error page when no backend is available, you can replace that page here.
+ <br/>
+ <br/>
+ <?
+ haproxy_htmllist("table_errorfile", $a_errorfiles, $fields_errorfile);
+ ?>
+ </td>
+ </tr>
+ <tr><td>&nbsp;</td></tr>
+ <tr>
<td colspan="2" valign="top" class="listtopic">Advanced</td>
</tr>
<tr class="" align="left" id='Strict-Transport-Security'>
@@ -961,9 +999,11 @@ set by the 'retries' parameter.</div>
<?
phparray_to_javascriptarray($fields_servers,"fields_servers",Array('/*','/*/name','/*/type','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name'));
phparray_to_javascriptarray($fields_servers_details,"fields_details_servers",Array('/*','/*/name','/*/type'));
+ phparray_to_javascriptarray($fields_errorfile,"fields_errorfile",Array('/*','/*/name','/*/type','/*/size','/*/items','/*/items/*','/*/items/*/*','/*/items/*/*/name'));
phparray_to_javascriptarray($a_checktypes,"checktypes",Array('/*','/*/name','/*/descr'));
phparray_to_javascriptarray($a_cookiemode,"cookiemode",Array('/*','/*/name','/*/descr'));
phparray_to_javascriptarray($a_sticky_type,"sticky_type",Array('/*','/*/descr','/*/cookiedescr'));
+ phparray_to_javascriptarray($a_files,"a_files",Array('/*','/*/name','/*/descr'));
?>
browser_InnerText_support = (document.getElementsByTagName("body")[0].innerText != undefined) ? true : false;
diff --git a/config/haproxy-devel/pkg_haproxy_tabs.inc b/config/haproxy-devel/pkg_haproxy_tabs.inc
index 8cb280f8..f49d2b67 100644
--- a/config/haproxy-devel/pkg_haproxy_tabs.inc
+++ b/config/haproxy-devel/pkg_haproxy_tabs.inc
@@ -12,7 +12,9 @@ $haproxy_tab_array['haproxy'] = array();
$haproxy_tab_array['haproxy']['settings'] = Array(name => "Settings", url => "haproxy_global.php");
$haproxy_tab_array['haproxy']['frontend'] = Array(name => "Frontend", url => "haproxy_listeners.php");
$haproxy_tab_array['haproxy']['backend'] = Array(name => "Backend", url => "haproxy_pools.php");
+$haproxy_tab_array['haproxy']['files'] = Array(name => "Files", url => "haproxy_files.php");
$haproxy_tab_array['haproxy']['stats'] = Array(name => "Stats", url => "haproxy_stats.php");
+$haproxy_tab_array['haproxy']['statsfs'] = Array(name => "Stats FS", url => "haproxy_stats.php?haproxystats=1");
function haproxy_display_top_tabs_active($top_tabs, $activetab) {
$tab_array = array();