]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] stats improvements
authorEvan Hunt <each@isc.org>
Thu, 9 Jan 2014 23:14:57 +0000 (15:14 -0800)
committerEvan Hunt <each@isc.org>
Fri, 10 Jan 2014 02:46:25 +0000 (18:46 -0800)
3700. [func] Allow access to subgroups of XML statistics via
special URLs http://<server>:<port>/xml/v3/server,
/zones, /net, /tasks, /mem, and /status.  [RT #35115]

3699. [bug] Improvements to statistics channel XSL stylesheet:
the stylesheet can now be cached by the browser;
section headers are omitted from the stats display
when there is no data in those sections to be
displayed; counters are now right-justified for
easier readability. [RT #35117]

12 files changed:
CHANGES
bin/named/bind9.xsl
bin/named/bind9.xsl.h
bin/named/convertxsl.pl
bin/named/server.c
bin/named/statschannel.c
doc/arm/Bv9ARM-book.xml
lib/isc/httpd.c
lib/isc/include/isc/httpd.h
lib/isc/include/isc/types.h
lib/isc/unix/include/isc/time.h
lib/isc/unix/time.c

diff --git a/CHANGES b/CHANGES
index d465d087beeaf5ac5b581ebc16d722b18bfc5a28..62deca98577d818e8f270f965f00cf2b1f72d7f7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,14 @@
+3700.  [func]          Allow access to subgroups of XML statistics via
+                       special URLs http://<server>:<port>/xml/v3/server,
+                       /zones, /net, /tasks, /mem, and /status.  [RT #35115]
+
+3699.  [bug]           Improvements to statistics channel XSL stylesheet:
+                       the stylesheet can now be cached by the browser;
+                       section headers are omitted from the stats display
+                       when there is no data in those sections to be
+                       displayed; counters are now right-justified for
+                       easier readability. [RT #35117]
+
 3698.  [cleanup]       Replaced all uses of memcpy() with memmove().
                        [RT #35120]
 
index d7ceb48f683d0200ec36a52d5dac70e0c039a297..9d003830afd6349c69f188c8128745ede6384b2f 100644 (file)
 <!-- %Id: bind9.xsl,v 1.21 2009/01/27 23:47:54 tbox Exp % -->
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" version="1.0">
   <xsl:output method="html" indent="yes" version="4.0"/>
-  <xsl:template match="statistics[@version=&quot;3.1&quot;]">
+  <xsl:template match="statistics[@version=&quot;3.4&quot;]">
     <html>
       <head>
         <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
           <!-- Non Mozilla specific markup -->
           <script type="text/javascript" src="https://www.google.com/jsapi"/>
           <script type="text/javascript">
-        
-        google.load("visualization", "1", {packages:["corechart"]});
-        google.setOnLoadCallback(loadGraphs);
-
-        var graphs=[];
-        
-        function drawChart(chart_title,target,data) {
-          var data = google.visualization.arrayToDataTable(data);
-
-          var options = {
-            title: chart_title
-          };
-          
-          var chart = new google.visualization.BarChart(document.getElementById(target));
-          chart.draw(data, options);
-        }
-        
-        function loadGraphs(){
-          //alert("here we are!");
-          var g;
-            
-          // Server Incoming query Types
-          while(g = graphs.shift()){
-            // alert("going for: " + g.target);
-            if(g.data.length > 1){
-              drawChart(g.title,g.target,g.data);
+
+            google.load("visualization", "1", {packages:["corechart"]});
+            google.setOnLoadCallback(loadGraphs);
+
+            var graphs=[];
+
+            function drawChart(chart_title,target,style,data) {
+              var data = google.visualization.arrayToDataTable(data);
+
+              var options = {
+                title: chart_title
+              };
+
+              var chart;
+              if (style == "barchart") {
+                chart = new google.visualization.BarChart(document.getElementById(target));
+                chart.draw(data, options);
+              } else if (style == "piechart") {
+                chart = new google.visualization.PieChart(document.getElementById(target));
+                chart.draw(data, options);
+              }
+            }
+
+            function loadGraphs(){
+              var g;
+    
+              while(g = graphs.shift()){
+                // alert("going for: " + g.target);
+                if(g.data.length > 1){
+                  drawChart(g.title,g.target,g.style,g.data);
+                }
+              }
             }
-          }
-        }
-        
-            // Server Incoming Queries Types         
-           graphs.push({
-                        'title' : "Server Incoming Query Types",
-                        'target': 'chart_incoming_qtypes',
-                        'data': [['Type','Counter'],<xsl:for-each select="server/counters[@type=&quot;qtype&quot;]/counter">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]
-                        });
-
-
-           // Server Incoming Requests         
-           graphs.push({
-                        'title' : "Server Incoming Requests",
-                        'target': 'chart_incoming_requests',
-                        'data': [['Requests','Counter'],<xsl:for-each select="server/counters[@type=&quot;opcode&quot;]/counter">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]});
-        
-        
-        
-        
-      </script>
+
+            <xsl:if test="server/counters[@type=&quot;qtype&quot;]/counter">
+              // Server Incoming Query Types         
+              graphs.push({
+                           'title' : "Server Incoming Query Types",
+                           'target': 'chart_incoming_qtypes',
+                           'style': 'barchart',
+                           'data': [['Type','Counter'],<xsl:for-each select="server/counters[@type=&quot;qtype&quot;]/counter">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]
+                           });
+            </xsl:if>
+  
+            <xsl:if test="server/counters[@type=&quot;opcode&quot;]/counter">
+              // Server Incoming Requests by opcode
+              graphs.push({
+                           'title' : "Server Incoming Requests by DNS Opcode",
+                           'target': 'chart_incoming_opcodes',
+                           'style': 'barchart',
+                           'data': [['Opcode','Counter'],<xsl:for-each select="server/counters[@type=&quot;opcode&quot;]/counter[. &gt; 0 or substring(@name,1,3) != 'RES']">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]});
+            </xsl:if>
+          </script>
         </xsl:if>
         <style type="text/css">
      body {
       color: #000000;
       font-size: 10pt;
      }
-     
+
      .odd{
       background-color: #f0f0f0;
      }
-     
+
      .even{
       background-color: #ffffff;
      }
-     
+
      p.footer{
       font-style:italic;
       color: grey;
       border: 1px solid grey;
       width: 500px;
      }
-     
      table.counters th {
+      text-align: right;
+      border: 1px solid grey;
+      width: 150px;
+     }
+     table.counters td {
+      text-align: right;
+      font-family: monospace;
+     }
+     table.counters tr:hover{
+      background-color: #99ddff;
+     }
+
+     table.info {
+      border: 1px solid grey;
+      width: 500px;
+     }
+     table.info th {
       text-align: center;
       border: 1px solid grey;
-      width: 120px;
+      width: 150px;
      }
-    table.counters td{
-      text-align:center;
-      
-    }
-    
-    table.counters tr:hover{
+     table.info td {
+      text-align: center;
+     }
+     table.info tr:hover{
+      background-color: #99ddff;
+     }
+
+     table.tasks {
+      border: 1px solid grey;
+      width: 500px;
+     }
+     table.tasks th {
+      text-align: center;
+      border: 1px solid grey;
+      width: 150px;
+     }
+     table.tasks td {
+      text-align: right;
+      font-family: monospace;
+     }
+     table.tasks td:nth-child(2) {
+      text-align: center;
+     }
+     table.tasks td:nth-child(4) {
+      text-align: center;
+     }
+     table.tasks tr:hover{
       background-color: #99ddff;
-    }
+     }
+
+     table.netstat {
+      border: 1px solid grey;
+      width: 500px;
+     }
+     table.netstat th {
+      text-align: center;
+      border: 1px solid grey;
+      width: 150px;
+     }
+     table.netstat td {
+      text-align: center;
+     }
+     table.netstat td:nth-child(4) {
+      text-align: right;
+      font-family: monospace;
+     }
+     table.netstat td:nth-child(7) {
+      text-align: left;
+     }
+     table.netstat tr:hover{
+      background-color: #99ddff;
+     }
+
+     table.mctx  {
+      border: 1px solid grey;
+      width: 500px;
+     }
+     table.mctx th {
+      text-align: center;
+      border: 1px solid grey;
+     }
+     table.mctx td {
+      text-align: right;
+      font-family: monospace;
+     }
+     table.mctx td:nth-child(-n+2) {
+      text-align: left;
+      width: 100px;
+     }
+     table.mctx tr:hover{
+      background-color: #99ddff;
+     }
+
      .totals {
       background-color: rgb(1,169,206);
       color: #ffffff;
        width:500px;
        text-align:center;
      }
-     
+
      h3 {
        color: #444444;
        font-size: 12pt;
        width:500px;
        text-align:center;
-       
      }
      h4 {
         color:  rgb(1,169,206);
         font-size: 10pt;
        width:500px;
        text-align:center;
-        
      }
 
      .pie {
           <h1>ISC Bind 9 Configuration and Statistics</h1>
         </div>
         <hr/>
-        <h2>Server Times</h2>
-        <table class="counters">
+        <h2>Server Status</h2>
+        <table class="info">
           <tr>
             <th>Boot time:</th>
             <td>
           </tr>
         </table>
         <br/>
-        <h2>Incoming Requests</h2>
-        <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
-          <!-- Non Mozilla specific markup -->
-          <div class="pie" id="chart_incoming_requests">[no incoming requests]</div>
-        </xsl:if>
-        <table class="counters">
-          <xsl:for-each select="server/counters[@type=&quot;opcode&quot;]/counter">
-            <xsl:sort select="." data-type="number" order="descending"/>
+        <xsl:if test="server/counters[@type=&quot;opcode&quot;]/counter[. &gt; 0]">
+          <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
+            <h2>Incoming Requests by DNS Opcode</h2>
+            <!-- Non Mozilla specific markup -->
+            <div class="pie" id="chart_incoming_opcodes">
+              [cannot display chart]
+            </div>
+          </xsl:if>
+          <table class="counters">
+            <xsl:for-each select="server/counters[@type=&quot;opcode&quot;]/counter[. &gt; 0 or substring(@name,1,3) != 'RES']">
+              <xsl:sort select="." data-type="number" order="descending"/>
+              <tr>
+                <th>
+                  <xsl:value-of select="@name"/>
+                </th>
+                <td>
+                  <xsl:value-of select="."/>
+                </td>
+              </tr>
+            </xsl:for-each>
             <tr>
-              <th>
-                <xsl:value-of select="@name"/>
-              </th>
-              <td>
-                <xsl:value-of select="."/>
+              <th class="totals">Total:</th>
+              <td class="totals">
+                <xsl:value-of select="sum(server/counters[@type=&quot;opcode&quot;]/counter)"/>
               </td>
             </tr>
-          </xsl:for-each>
-          <tr>
-            <th class="totals">Total:</th>
-            <td class="totals">
-              <xsl:value-of select="sum(server/counters[@type=&quot;opcode&quot;]/counter)"/>
-            </td>
-          </tr>
-        </table>
-        <br/>
-        <h3>Incoming Queries by Type</h3>
-        <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
-          <!-- Non Mozilla specific markup -->
-          <div class="pie" id="chart_incoming_qtypes">[no incoming queries]</div>
+          </table>
+          <br/>
         </xsl:if>
-        <table class="counters">
-          <xsl:for-each select="server/counters[@type=&quot;qtype&quot;]/counter">
-            <xsl:sort select="." data-type="number" order="descending"/>
-            <xsl:variable name="css-class">
-              <xsl:choose>
-                <xsl:when test="position() mod 2 = 0">even</xsl:when>
-                <xsl:otherwise>odd</xsl:otherwise>
-              </xsl:choose>
-            </xsl:variable>
-            <tr class="{$css-class}">
-              <th>
-                <xsl:value-of select="@name"/>
-              </th>
-              <td>
-                <xsl:value-of select="."/>
-              </td>
-            </tr>
-          </xsl:for-each>
-          <tr>
-            <th class="totals">Total:</th>
-            <td class="totals">
-              <xsl:value-of select="sum(server/counters[@type=&quot;qtype&quot;]/counter)"/>
-            </td>
-          </tr>
-        </table>
-        <br/>
-        <h2>Outgoing Queries per view</h2>
-        <xsl:for-each select="views/view[count(counters[@type=&quot;resqtype&quot;]/counter) &gt; 0]">
-          <h3>View <xsl:value-of select="@name"/></h3>
+        <xsl:if test="server/counters[@type=&quot;qtype&quot;]/counter">
           <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
             <!-- Non Mozilla specific markup -->
-          <script type="text/javascript">
-                graphs.push({
-                              'title': "Outgoing queries for view: <xsl:value-of select="@name"/>",
-                              'target': 'chart_outgoing_queries_view_<xsl:value-of select="@name"/>',
-                              'data': [['Type','Counter'],<xsl:for-each select="counters[@type=&quot;resqtype&quot;]/counter">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]
-                              });
-                              
-            </script>
-          <xsl:variable name="target">
-            <xsl:value-of select="@name"/>
-          </xsl:variable>
-            <div class="pie" id="chart_outgoing_queries_view_{$target}"/>
+            <h3>Incoming Queries by Query Type</h3>
+            <div class="pie" id="chart_incoming_qtypes">
+              [cannot display chart]
+            </div>
           </xsl:if>
           <table class="counters">
-            <xsl:for-each select="counters[@type=&quot;resqtype&quot;]/counter">
+            <xsl:for-each select="server/counters[@type=&quot;qtype&quot;]/counter">
               <xsl:sort select="." data-type="number" order="descending"/>
-              <xsl:variable name="css-class1">
+              <xsl:variable name="css-class">
                 <xsl:choose>
                   <xsl:when test="position() mod 2 = 0">even</xsl:when>
                   <xsl:otherwise>odd</xsl:otherwise>
                 </xsl:choose>
               </xsl:variable>
-              <tr class="{$css-class1}">
+              <tr class="{$css-class}">
                 <th>
                   <xsl:value-of select="@name"/>
                 </th>
                 </td>
               </tr>
             </xsl:for-each>
+            <tr>
+              <th class="totals">Total:</th>
+              <td class="totals">
+                <xsl:value-of select="sum(server/counters[@type=&quot;qtype&quot;]/counter)"/>
+              </td>
+            </tr>
           </table>
           <br/>
-        </xsl:for-each>
-        <h2>Server Statistics</h2>
-        <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
-          <!-- Non Mozilla specific markup -->
-        <script type="text/javascript">
-                graphs.push({
-                              'title' : "Server Counters",
-                              'target': 'chart_server_nsstat_restype',
-                              'data': [['Type','Counter'],<xsl:for-each select="server/counters[@type=&quot;nsstat&quot;]/counter[.&gt;0]">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]
-                              });
-                              
-            </script>
-          <div class="pie" id="chart_server_nsstat_restype"/>
         </xsl:if>
-        <table class="counters">
-          <xsl:for-each select="server/counters[@type=&quot;nsstat&quot;]/counter[.&gt;0]">
-            <xsl:sort select="." data-type="number" order="descending"/>
-            <xsl:variable name="css-class2">
-              <xsl:choose>
-                <xsl:when test="position() mod 2 = 0">even</xsl:when>
-                <xsl:otherwise>odd</xsl:otherwise>
-              </xsl:choose>
+        <xsl:if test="views/view[count(counters[@type=&quot;resqtype&quot;]/counter) &gt; 0]">
+          <h2>Outgoing Queries per view</h2>
+          <xsl:for-each select="views/view[count(counters[@type=&quot;resqtype&quot;]/counter) &gt; 0]">
+            <h3>View <xsl:value-of select="@name"/></h3>
+            <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
+              <!-- Non Mozilla specific markup -->
+            <script type="text/javascript">
+                  graphs.push({
+                                'title': "Outgoing Queries for view: <xsl:value-of select="@name"/>",
+                                'target': 'chart_outgoing_queries_view_<xsl:value-of select="@name"/>',
+                                'style': 'barchart',
+                                'data': [['Type','Counter'],<xsl:for-each select="counters[@type=&quot;resqtype&quot;]/counter">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]
+                                });
+              </script>
+            <xsl:variable name="target">
+              <xsl:value-of select="@name"/>
             </xsl:variable>
-            <tr class="{$css-class2}">
-              <th>
-                <xsl:value-of select="@name"/>
-              </th>
-              <td>
-                <xsl:value-of select="."/>
-              </td>
-            </tr>
+              <div class="pie" id="chart_outgoing_queries_view_{$target}">[no data to display]</div>
+            </xsl:if>
+            <table class="counters">
+              <xsl:for-each select="counters[@type=&quot;resqtype&quot;]/counter">
+                <xsl:sort select="." data-type="number" order="descending"/>
+                <xsl:variable name="css-class1">
+                  <xsl:choose>
+                    <xsl:when test="position() mod 2 = 0">even</xsl:when>
+                    <xsl:otherwise>odd</xsl:otherwise>
+                  </xsl:choose>
+                </xsl:variable>
+                <tr class="{$css-class1}">
+                  <th>
+                    <xsl:value-of select="@name"/>
+                  </th>
+                  <td>
+                    <xsl:value-of select="."/>
+                  </td>
+                </tr>
+              </xsl:for-each>
+            </table>
+            <br/>
           </xsl:for-each>
-        </table>
-        <br/>
-        <h2>Zone Maintenance Statistics</h2>
-        <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
-        <script type="text/javascript">
-                      graphs.push({
-                                    'title' : "Zone Maintenance Stats",
-                                    'target': 'chart_server_zone_maint',
-                                    'data': [['Type','Counter'],<xsl:for-each select="server/counters[@type=&quot;zonestat&quot;]/counter">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]
-                                    });
-
-                  </script>
-          <!-- Non Mozilla specific markup -->
-          <div class="pie" id="chart_server_zone_maint"/>
         </xsl:if>
-        <table class="counters">
-          <xsl:for-each select="server/counters[@type=&quot;zonestat&quot;]/counter">
-            <xsl:sort select="." data-type="number" order="descending"/>
-            <xsl:variable name="css-class3">
-              <xsl:choose>
-                <xsl:when test="position() mod 2 = 0">even</xsl:when>
-                <xsl:otherwise>odd</xsl:otherwise>
-              </xsl:choose>
-            </xsl:variable>
-            <tr class="{$css-class3}">
-              <th>
-                <xsl:value-of select="@name"/>
-              </th>
-              <td>
-                <xsl:value-of select="."/>
-              </td>
-            </tr>
-          </xsl:for-each>
-        </table>
-        <h2>Resolver Statistics (Common)</h2>
-        <table class="counters">
-          <xsl:for-each select="server/counters[@type=&quot;resstat&quot;]/counter">
-            <xsl:sort select="." data-type="number" order="descending"/>
-            <xsl:variable name="css-class4">
-              <xsl:choose>
-                <xsl:when test="position() mod 2 = 0">even</xsl:when>
-                <xsl:otherwise>odd</xsl:otherwise>
-              </xsl:choose>
-            </xsl:variable>
-            <tr class="{$css-class4}">
-              <th>
-                <xsl:value-of select="@name"/>
-              </th>
-              <td>
-                <xsl:value-of select="."/>
-              </td>
-            </tr>
-          </xsl:for-each>
-        </table>
-        <xsl:for-each select="views/view">
-          <h3>Resolver Statistics for View <xsl:value-of select="@name"/></h3>
+        <xsl:if test="server/counters[@type=&quot;nsstat&quot;]/counter[.&gt;0]">
+          <h2>Server Statistics</h2>
+          <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
+            <!-- Non Mozilla specific markup -->
+          <script type="text/javascript">
+                  graphs.push({
+                                'title' : "Server Counters",
+                                'target': 'chart_server_nsstat_restype',
+                                'style': 'barchart',
+                                'data': [['Type','Counter'],<xsl:for-each select="server/counters[@type=&quot;nsstat&quot;]/counter[.&gt;0]">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]
+                                });
+              </script>
+            <div class="pie" id="chart_server_nsstat_restype">[no data to display]</div>
+          </xsl:if>
           <table class="counters">
-            <xsl:for-each select="counters[@type=&quot;resstats&quot;]/counter[.&gt;0]">
+            <xsl:for-each select="server/counters[@type=&quot;nsstat&quot;]/counter[.&gt;0]">
               <xsl:sort select="." data-type="number" order="descending"/>
-              <xsl:variable name="css-class5">
+              <xsl:variable name="css-class2">
                 <xsl:choose>
                   <xsl:when test="position() mod 2 = 0">even</xsl:when>
                   <xsl:otherwise>odd</xsl:otherwise>
                 </xsl:choose>
               </xsl:variable>
-              <tr class="{$css-class5}">
+              <tr class="{$css-class2}">
                 <th>
                   <xsl:value-of select="@name"/>
                 </th>
               </tr>
             </xsl:for-each>
           </table>
-        </xsl:for-each>
-
-
-        <xsl:for-each select="views/view">
-          <h3>ADB Statistics for View <xsl:value-of select="@name"/></h3>
+          <br/>
+        </xsl:if>
+        <xsl:if test="server/counters[@type=&quot;zonestat&quot;]/counter[.&gt;0]">
+          <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
+            <h2>Zone Maintenance Statistics</h2>
+            <script type="text/javascript">
+                  graphs.push({
+                                'title' : "Zone Maintenance Stats",
+                                'target': 'chart_server_zone_maint',
+                                'style': 'barchart',
+                                'data': [['Type','Counter'],<xsl:for-each select="server/counters[@type=&quot;zonestat&quot;]/counter[.&gt;0]">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]
+                                });
+            </script>
+            <!-- Non Mozilla specific markup -->
+            <div class="pie" id="chart_server_zone_maint">[no data to display]</div>
+          </xsl:if>
           <table class="counters">
-            <xsl:for-each select="counters[@type=&quot;adbstat&quot;]/counter[.&gt;0]">
+            <xsl:for-each select="server/counters[@type=&quot;zonestat&quot;]/counter">
               <xsl:sort select="." data-type="number" order="descending"/>
-              <xsl:variable name="css-class5">
+              <xsl:variable name="css-class3">
                 <xsl:choose>
                   <xsl:when test="position() mod 2 = 0">even</xsl:when>
                   <xsl:otherwise>odd</xsl:otherwise>
                 </xsl:choose>
               </xsl:variable>
-              <tr class="{$css-class5}">
+              <tr class="{$css-class3}">
                 <th>
                   <xsl:value-of select="@name"/>
                 </th>
               </tr>
             </xsl:for-each>
           </table>
-        </xsl:for-each>
-
-        <xsl:for-each select="views/view">
-          <h3>Cache Statistics for View <xsl:value-of select="@name"/></h3>
+        </xsl:if>
+        <xsl:if test="server/counters[@type=&quot;resstat&quot;]/counter[.&gt;0]">
+          <h2>Resolver Statistics (Common)</h2>
           <table class="counters">
-            <xsl:for-each select="counters[@type=&quot;cachestats&quot;]/counter[.&gt;0]">
+            <xsl:for-each select="server/counters[@type=&quot;resstat&quot;]/counter">
               <xsl:sort select="." data-type="number" order="descending"/>
-              <xsl:variable name="css-class5">
+              <xsl:variable name="css-class4">
                 <xsl:choose>
                   <xsl:when test="position() mod 2 = 0">even</xsl:when>
                   <xsl:otherwise>odd</xsl:otherwise>
                 </xsl:choose>
               </xsl:variable>
-              <tr class="{$css-class5}">
+              <tr class="{$css-class4}">
                 <th>
                   <xsl:value-of select="@name"/>
                 </th>
               </tr>
             </xsl:for-each>
           </table>
+        </xsl:if>
+        <xsl:for-each select="views/view">
+          <xsl:if test="counters[@type=&quot;resstats&quot;]/counter[.&gt;0]">
+            <h3>Resolver Statistics for View <xsl:value-of select="@name"/></h3>
+            <table class="counters">
+              <xsl:for-each select="counters[@type=&quot;resstats&quot;]/counter[.&gt;0]">
+                <xsl:sort select="." data-type="number" order="descending"/>
+                <xsl:variable name="css-class5">
+                  <xsl:choose>
+                    <xsl:when test="position() mod 2 = 0">even</xsl:when>
+                    <xsl:otherwise>odd</xsl:otherwise>
+                  </xsl:choose>
+                </xsl:variable>
+                <tr class="{$css-class5}">
+                  <th>
+                    <xsl:value-of select="@name"/>
+                  </th>
+                  <td>
+                    <xsl:value-of select="."/>
+                  </td>
+                </tr>
+              </xsl:for-each>
+            </table>
+          </xsl:if>
+        </xsl:for-each>
+        <xsl:for-each select="views/view">
+          <xsl:if test="counters[@type=&quot;adbstat&quot;]/counter[.&gt;0]">
+            <h3>ADB Statistics for View <xsl:value-of select="@name"/></h3>
+            <table class="counters">
+              <xsl:for-each select="counters[@type=&quot;adbstat&quot;]/counter[.&gt;0]">
+                <xsl:sort select="." data-type="number" order="descending"/>
+                <xsl:variable name="css-class5">
+                  <xsl:choose>
+                    <xsl:when test="position() mod 2 = 0">even</xsl:when>
+                    <xsl:otherwise>odd</xsl:otherwise>
+                  </xsl:choose>
+                </xsl:variable>
+                <tr class="{$css-class5}">
+                  <th>
+                    <xsl:value-of select="@name"/>
+                  </th>
+                  <td>
+                    <xsl:value-of select="."/>
+                  </td>
+                </tr>
+              </xsl:for-each>
+            </table>
+          </xsl:if>
         </xsl:for-each>
 
+        <xsl:for-each select="views/view">
+          <xsl:if test="counters[@type=&quot;cachestats&quot;]/counter[.&gt;0]">
+            <h3>Cache Statistics for View <xsl:value-of select="@name"/></h3>
+            <table class="counters">
+              <xsl:for-each select="counters[@type=&quot;cachestats&quot;]/counter[.&gt;0]">
+                <xsl:sort select="." data-type="number" order="descending"/>
+                <xsl:variable name="css-class5">
+                  <xsl:choose>
+                    <xsl:when test="position() mod 2 = 0">even</xsl:when>
+                    <xsl:otherwise>odd</xsl:otherwise>
+                  </xsl:choose>
+                </xsl:variable>
+                <tr class="{$css-class5}">
+                  <th>
+                    <xsl:value-of select="@name"/>
+                  </th>
+                  <td>
+                    <xsl:value-of select="."/>
+                  </td>
+                </tr>
+              </xsl:for-each>
+            </table>
+          </xsl:if>
+        </xsl:for-each>
 
-        <h3>Cache DB RRsets for View <xsl:value-of select="@name"/></h3>
         <xsl:for-each select="views/view">
+          <xsl:if test="cache/rrset">
+            <h3>Cache DB RRsets for View <xsl:value-of select="@name"/></h3>
+            <table class="counters">
+              <xsl:for-each select="cache/rrset">
+                <xsl:variable name="css-class6">
+                  <xsl:choose>
+                    <xsl:when test="position() mod 2 = 0">even</xsl:when>
+                    <xsl:otherwise>odd</xsl:otherwise>
+                  </xsl:choose>
+                </xsl:variable>
+                <tr class="{$css-class6}">
+                  <th>
+                    <xsl:value-of select="name"/>
+                  </th>
+                  <td>
+                    <xsl:value-of select="counter"/>
+                  </td>
+                </tr>
+              </xsl:for-each>
+            </table>
+            <br/>
+          </xsl:if>
+        </xsl:for-each>
+
+        <xsl:if test="server/counters[@type=&quot;sockstat&quot;]/counter[.&gt;0]">
+          <h2>Socket I/O Statistics</h2>
           <table class="counters">
-            <xsl:for-each select="cache/rrset">
-              <xsl:variable name="css-class6">
+            <xsl:for-each select="server/counters[@type=&quot;sockstat&quot;]/counter[.&gt;0]">
+              <xsl:variable name="css-class7">
                 <xsl:choose>
                   <xsl:when test="position() mod 2 = 0">even</xsl:when>
                   <xsl:otherwise>odd</xsl:otherwise>
                 </xsl:choose>
               </xsl:variable>
-              <tr class="{$css-class6}">
+              <tr class="{$css-class7}">
                 <th>
-                  <xsl:value-of select="name"/>
+                  <xsl:value-of select="@name"/>
                 </th>
                 <td>
-                  <xsl:value-of select="counter"/>
+                  <xsl:value-of select="."/>
                 </td>
               </tr>
             </xsl:for-each>
           </table>
           <br/>
-        </xsl:for-each>
-        <h2>Socket I/O Statistics</h2>
-        <table class="counters">
-          <xsl:for-each select="server/counters[@type=&quot;sockstat&quot;]/counter[.&gt;0]">
-            <xsl:variable name="css-class7">
-              <xsl:choose>
-                <xsl:when test="position() mod 2 = 0">even</xsl:when>
-                <xsl:otherwise>odd</xsl:otherwise>
-              </xsl:choose>
+        </xsl:if>
+        <xsl:if test="views/view[zones/zone/counters[@type=&quot;qtype&quot;]/counter &gt;0]">
+          <h2>Received QTYPES per view/zone</h2>
+          <xsl:for-each select="views/view[zones/zone/counters[@type=&quot;qtype&quot;]/counter &gt;0]">
+            <h3>View <xsl:value-of select="@name"/></h3>
+            <xsl:variable name="thisview">
+              <xsl:value-of select="@name"/>
             </xsl:variable>
-            <tr class="{$css-class7}">
-              <th>
-                <xsl:value-of select="@name"/>
-              </th>
-              <td>
-                <xsl:value-of select="."/>
-              </td>
-            </tr>
-          </xsl:for-each>
-        </table>
-        <br/>
-        <br/>
-        <h2>Response Codes per view/zone</h2>
-        <xsl:for-each select="views/view[zones/zone/counters[@type=&quot;rcode&quot;]/counter &gt;0]">
-          <h3>View <xsl:value-of select="@name"/></h3>
-          <xsl:variable name="thisview">
-            <xsl:value-of select="@name"/>
-          </xsl:variable>
-          <xsl:for-each select="zones/zone">
-            <xsl:if test="counters[@type=&quot;rcode&quot;]/counter[. &gt; 0]">
-              <h4>Zone <xsl:value-of select="@name"/></h4>
-              <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
-                <!-- Non Mozilla specific markup -->
-              <script type="text/javascript">
-                      graphs.push({
-                                    'title': "Response Codes for zone <xsl:value-of select="@name"/>",
-                                    'target': 'chart_rescode_<xsl:value-of select="../../@name"/>_<xsl:value-of select="@name"/>',
-                                    'data': [['Type','Counter'],<xsl:for-each select="counters[@type=&quot;rcode&quot;]/counter[.&gt;0 and @name != &quot;QryAuthAns&quot;]">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]
-                                    });
-
-                  </script>
-              <xsl:variable name="target">
-                <xsl:value-of select="@name"/>
-              </xsl:variable>
-                <div class="pie" id="chart_rescode_{$thisview}_{$target}"/>
+            <xsl:for-each select="zones/zone">
+              <xsl:if test="counters[@type=&quot;qtype&quot;]/counter[count(.) &gt; 0]">
+                <h4>Zone <xsl:value-of select="@name"/></h4>
+                <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
+                  <!-- Non Mozilla specific markup -->
+                <script type="text/javascript">
+                        graphs.push({
+                                      'title': "Query types for zone <xsl:value-of select="@name"/>",
+                                      'target': 'chart_qtype_<xsl:value-of select="../../@name"/>_<xsl:value-of select="@name"/>',
+                                      'style': 'barchart',
+                                      'data': [['Type','Counter'],<xsl:for-each select="counters[@type=&quot;qtype&quot;]/counter[.&gt;0 and @name != &quot;QryAuthAns&quot;]">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]
+                                      });
+
+                    </script>
+                <xsl:variable name="target">
+                  <xsl:value-of select="@name"/>
+                </xsl:variable>
+                  <div class="pie" id="chart_qtype_{$thisview}_{$target}">[no data to display]</div>
+                </xsl:if>
+                <table class="counters">
+                  <xsl:for-each select="counters[@type=&quot;qtype&quot;]/counter">
+                    <xsl:sort select="."/>
+                    <xsl:variable name="css-class10">
+                      <xsl:choose>
+                        <xsl:when test="position() mod 2 = 0">even</xsl:when>
+                        <xsl:otherwise>odd</xsl:otherwise>
+                      </xsl:choose>
+                    </xsl:variable>
+                    <tr class="{$css-class10}">
+                      <th>
+                        <xsl:value-of select="@name"/>
+                      </th>
+                      <td>
+                        <xsl:value-of select="."/>
+                      </td>
+                    </tr>
+                  </xsl:for-each>
+                </table>
               </xsl:if>
-              <table class="counters">
-                <xsl:for-each select="counters[@type=&quot;rcode&quot;]/counter[.&gt;0 and @name != &quot;QryAuthAns&quot;]">
-                  <xsl:sort select="."/>
-                  <xsl:variable name="css-class10">
-                    <xsl:choose>
-                      <xsl:when test="position() mod 2 = 0">even</xsl:when>
-                      <xsl:otherwise>odd</xsl:otherwise>
-                    </xsl:choose>
-                  </xsl:variable>
-                  <tr class="{$css-class10}">
-                    <th>
-                      <xsl:value-of select="@name"/>
-                    </th>
-                    <td>
-                      <xsl:value-of select="."/>
-                    </td>
-                  </tr>
-                </xsl:for-each>
-              </table>
-            </xsl:if>
+            </xsl:for-each>
           </xsl:for-each>
-        </xsl:for-each>
-        <h2>Received QTYPES per view/zone</h2>
-        <xsl:for-each select="views/view[zones/zone/counters[@type=&quot;qtype&quot;]/counter &gt;0]">
-          <h3>View <xsl:value-of select="@name"/></h3>
-          <xsl:variable name="thisview2">
-            <xsl:value-of select="@name"/>
-          </xsl:variable>
-          <xsl:for-each select="zones/zone">
-            <xsl:if test="counters[@type=&quot;qtype&quot;]/counter[count(.) &gt; 0]">
-              <h4>Zone <xsl:value-of select="@name"/></h4>
-              <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
-                <!-- Non Mozilla specific markup -->
-              <script type="text/javascript">
-                      graphs.push({
-                                    'title': "Query Types for zone <xsl:value-of select="@name"/>",
-                                    'target': 'chart_qtype_<xsl:value-of select="../../@name"/>_<xsl:value-of select="@name"/>',
-                                    'data': [['Type','Counter'],<xsl:for-each select="counters[@type=&quot;qtype&quot;]/counter[.&gt;0 and @name != &quot;QryAuthAns&quot;]">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]
-                                    });
-
-                  </script>
-              <xsl:variable name="target">
-                <xsl:value-of select="@name"/>
-              </xsl:variable>
-                <div class="pie" id="chart_qtype_{$thisview2}_{$target}"/>
+        </xsl:if>
+        <xsl:if test="views/view[zones/zone/counters[@type=&quot;rcode&quot;]/counter &gt;0]">
+          <h2>Response Codes per view/zone</h2>
+          <xsl:for-each select="views/view[zones/zone/counters[@type=&quot;rcode&quot;]/counter &gt;0]">
+            <h3>View <xsl:value-of select="@name"/></h3>
+            <xsl:variable name="thisview2">
+              <xsl:value-of select="@name"/>
+            </xsl:variable>
+            <xsl:for-each select="zones/zone">
+              <xsl:if test="counters[@type=&quot;rcode&quot;]/counter[. &gt; 0]">
+                <h4>Zone <xsl:value-of select="@name"/></h4>
+                <xsl:if test="system-property('xsl:vendor')!='Transformiix'">
+                  <!-- Non Mozilla specific markup -->
+                <script type="text/javascript">
+                        graphs.push({
+                                      'title': "Response codes for zone <xsl:value-of select="@name"/>",
+                                      'target': 'chart_rescode_<xsl:value-of select="../../@name"/>_<xsl:value-of select="@name"/>',
+                                      'style': 'barchart',
+                                      'data': [['Type','Counter'],<xsl:for-each select="counters[@type=&quot;rcode&quot;]/counter[.&gt;0 and @name != &quot;QryAuthAns&quot;]">['<xsl:value-of select="@name"/>',<xsl:value-of select="."/>],</xsl:for-each>]
+                                      });
+
+                </script>
+                <xsl:variable name="target">
+                  <xsl:value-of select="@name"/>
+                </xsl:variable>
+                  <div class="pie" id="chart_rescode_{$thisview2}_{$target}">[no data to display]</div>
+                </xsl:if>
+                <table class="counters">
+                  <xsl:for-each select="counters[@type=&quot;rcode&quot;]/counter[.&gt;0 and @name != &quot;QryAuthAns&quot;]">
+                    <xsl:sort select="."/>
+                    <xsl:variable name="css-class11">
+                      <xsl:choose>
+                        <xsl:when test="position() mod 2 = 0">even</xsl:when>
+                        <xsl:otherwise>odd</xsl:otherwise>
+                      </xsl:choose>
+                    </xsl:variable>
+                    <tr class="{$css-class11}">
+                      <th>
+                        <xsl:value-of select="@name"/>
+                      </th>
+                      <td>
+                        <xsl:value-of select="."/>
+                      </td>
+                    </tr>
+                  </xsl:for-each>
+                </table>
               </xsl:if>
-              <table class="counters">
-                <xsl:for-each select="counters[@type=&quot;qtype&quot;]/counter">
-                  <xsl:sort select="."/>
-                  <xsl:variable name="css-class11">
-                    <xsl:choose>
-                      <xsl:when test="position() mod 2 = 0">even</xsl:when>
-                      <xsl:otherwise>odd</xsl:otherwise>
-                    </xsl:choose>
-                  </xsl:variable>
-                  <tr class="{$css-class11}">
-                    <th>
-                      <xsl:value-of select="@name"/>
-                    </th>
-                    <td>
-                      <xsl:value-of select="."/>
-                    </td>
-                  </tr>
-                </xsl:for-each>
-              </table>
-            </xsl:if>
+            </xsl:for-each>
           </xsl:for-each>
-        </xsl:for-each>
-        <h2>Network Status</h2>
-        <table class="counters">
-          <tr>
-            <th>ID</th>
-            <th>Name</th>
-            <th>Type</th>
-            <th>References</th>
-            <th>LocalAddress</th>
-            <th>PeerAddress</th>
-            <th>State</th>
-          </tr>
-          <xsl:for-each select="socketmgr/sockets/socket">
-            <xsl:sort select="id"/>
-            <xsl:variable name="css-class12">
-              <xsl:choose>
-                <xsl:when test="position() mod 2 = 0">even</xsl:when>
-                <xsl:otherwise>odd</xsl:otherwise>
-              </xsl:choose>
-            </xsl:variable>
-            <tr class="{$css-class12}">
-              <td>
-                <xsl:value-of select="id"/>
-              </td>
-              <td>
-                <xsl:value-of select="name"/>
-              </td>
-              <td>
-                <xsl:value-of select="type"/>
-              </td>
-              <td>
-                <xsl:value-of select="references"/>
-              </td>
-              <td>
-                <xsl:value-of select="local-address"/>
-              </td>
-              <td>
-                <xsl:value-of select="peer-address"/>
-              </td>
-              <td>
-                <xsl:for-each select="states">
-                  <xsl:value-of select="."/>
-                </xsl:for-each>
-              </td>
+        </xsl:if>
+        <xsl:if test="socketmgr/sockets/socket">
+          <h2>Network Status</h2>
+          <table class="netstat">
+            <tr>
+              <th>ID</th>
+              <th>Name</th>
+              <th>Type</th>
+              <th>References</th>
+              <th>LocalAddress</th>
+              <th>PeerAddress</th>
+              <th>State</th>
             </tr>
-          </xsl:for-each>
-        </table>
-        <br/>
-        <h2>Task Manager Configuration</h2>
-        <table class="counters">
-          <tr>
-            <th class="even">Thread-Model</th>
-            <td>
-              <xsl:value-of select="taskmgr/thread-model/type"/>
-            </td>
-          </tr>
-          <tr class="odd">
-            <th>Worker Threads</th>
-            <td>
-              <xsl:value-of select="taskmgr/thread-model/worker-threads"/>
-            </td>
-          </tr>
-          <tr class="even">
-            <th>Default Quantum</th>
-            <td>
-              <xsl:value-of select="taskmgr/thread-model/default-quantum"/>
-            </td>
-          </tr>
-          <tr class="odd">
-            <th>Tasks Running</th>
-            <td>
-              <xsl:value-of select="taskmgr/thread-model/tasks-running"/>
-            </td>
-          </tr>
-          <tr class="odd">
-            <th>Tasks Ready</th>
-            <td>
-              <xsl:value-of select="taskmgr/thread-model/tasks-ready"/>
-            </td>
-          </tr>
-        </table>
-        <br/>
-        <h2>Tasks</h2>
-        <table class="counters">
-          <tr>
-            <th>ID</th>
-            <th>Name</th>
-            <th>References</th>
-            <th>State</th>
-            <th>Quantum</th>
-            <th>Events</th>
-          </tr>
-          <xsl:for-each select="taskmgr/tasks/task">
-            <xsl:sort select="name"/>
-            <xsl:variable name="css-class14">
-              <xsl:choose>
-                <xsl:when test="position() mod 2 = 0">even</xsl:when>
-                <xsl:otherwise>odd</xsl:otherwise>
-              </xsl:choose>
-            </xsl:variable>
-            <tr class="{$css-class14}">
-              <td>
-                <xsl:value-of select="id"/>
-              </td>
-              <td>
-                <xsl:value-of select="name"/>
-              </td>
-              <td>
-                <xsl:value-of select="references"/>
-              </td>
-              <td>
-                <xsl:value-of select="state"/>
-              </td>
-              <td>
-                <xsl:value-of select="quantum"/>
-              </td>
+            <xsl:for-each select="socketmgr/sockets/socket">
+              <xsl:sort select="id"/>
+              <xsl:variable name="css-class12">
+                <xsl:choose>
+                  <xsl:when test="position() mod 2 = 0">even</xsl:when>
+                  <xsl:otherwise>odd</xsl:otherwise>
+                </xsl:choose>
+              </xsl:variable>
+              <tr class="{$css-class12}">
+                <td>
+                  <xsl:value-of select="id"/>
+                </td>
+                <td>
+                  <xsl:value-of select="name"/>
+                </td>
+                <td>
+                  <xsl:value-of select="type"/>
+                </td>
+                <td>
+                  <xsl:value-of select="references"/>
+                </td>
+                <td>
+                  <xsl:value-of select="local-address"/>
+                </td>
+                <td>
+                  <xsl:value-of select="peer-address"/>
+                </td>
+                <td>
+                  <xsl:for-each select="states">
+                    <xsl:value-of select="."/>
+                  </xsl:for-each>
+                </td>
+              </tr>
+            </xsl:for-each>
+          </table>
+          <br/>
+        </xsl:if>
+        <xsl:if test="taskmgr/thread-model/type">
+          <h2>Task Manager Configuration</h2>
+          <table class="counters">
+            <tr>
+              <th class="even">Thread-Model</th>
               <td>
-                <xsl:value-of select="events"/>
+                <xsl:value-of select="taskmgr/thread-model/type"/>
               </td>
             </tr>
-          </xsl:for-each>
-        </table>
-        <br/>
-        <h2>Memory Usage Summary</h2>
-        <table class="counters">
-          <xsl:for-each select="memory/summary/*">
-            <xsl:variable name="css-class13">
-              <xsl:choose>
-                <xsl:when test="position() mod 2 = 0">even</xsl:when>
-                <xsl:otherwise>odd</xsl:otherwise>
-              </xsl:choose>
-            </xsl:variable>
-            <tr class="{$css-class13}">
-              <th>
-                <xsl:value-of select="name()"/>
-              </th>
+            <tr class="odd">
+              <th>Worker Threads</th>
               <td>
-                <xsl:value-of select="."/>
+                <xsl:value-of select="taskmgr/thread-model/worker-threads"/>
               </td>
             </tr>
-          </xsl:for-each>
-        </table>
-        <br/>
-        <h2>Memory Contexts</h2>
-        <table class="counters">
-          <tr>
-            <th>ID</th>
-            <th>Name</th>
-            <th>References</th>
-            <th>TotalUse</th>
-            <th>InUse</th>
-            <th>MaxUse</th>
-            <th>BlockSize</th>
-            <th>Pools</th>
-            <th>HiWater</th>
-            <th>LoWater</th>
-          </tr>
-          <xsl:for-each select="memory/contexts/context">
-            <xsl:sort select="total" data-type="number" order="descending"/>
-            <xsl:variable name="css-class14">
-              <xsl:choose>
-                <xsl:when test="position() mod 2 = 0">even</xsl:when>
-                <xsl:otherwise>odd</xsl:otherwise>
-              </xsl:choose>
-            </xsl:variable>
-            <tr class="{$css-class14}">
-              <td>
-                <xsl:value-of select="id"/>
-              </td>
-              <td>
-                <xsl:value-of select="name"/>
-              </td>
-              <td>
-                <xsl:value-of select="references"/>
-              </td>
-              <td>
-                <xsl:value-of select="total"/>
-              </td>
-              <td>
-                <xsl:value-of select="inuse"/>
-              </td>
-              <td>
-                <xsl:value-of select="maxinuse"/>
-              </td>
-              <td>
-                <xsl:value-of select="blocksize"/>
-              </td>
+            <tr class="even">
+              <th>Default Quantum</th>
               <td>
-                <xsl:value-of select="pools"/>
+                <xsl:value-of select="taskmgr/thread-model/default-quantum"/>
               </td>
+            </tr>
+            <tr class="odd">
+              <th>Tasks Running</th>
               <td>
-                <xsl:value-of select="hiwater"/>
+                <xsl:value-of select="taskmgr/thread-model/tasks-running"/>
               </td>
+            </tr>
+            <tr class="even">
+              <th>Tasks Ready</th>
               <td>
-                <xsl:value-of select="lowater"/>
+                <xsl:value-of select="taskmgr/thread-model/tasks-ready"/>
               </td>
             </tr>
-          </xsl:for-each>
-        </table>
+          </table>
+          <br/>
+        </xsl:if>
+        <xsl:if test="taskmgr/tasks/task">
+          <h2>Tasks</h2>
+          <table class="tasks">
+            <tr>
+              <th>ID</th>
+              <th>Name</th>
+              <th>References</th>
+              <th>State</th>
+              <th>Quantum</th>
+              <th>Events</th>
+            </tr>
+            <xsl:for-each select="taskmgr/tasks/task">
+              <xsl:sort select="name"/>
+              <xsl:variable name="css-class14">
+                <xsl:choose>
+                  <xsl:when test="position() mod 2 = 0">even</xsl:when>
+                  <xsl:otherwise>odd</xsl:otherwise>
+                </xsl:choose>
+              </xsl:variable>
+              <tr class="{$css-class14}">
+                <td>
+                  <xsl:value-of select="id"/>
+                </td>
+                <td>
+                  <xsl:value-of select="name"/>
+                </td>
+                <td>
+                  <xsl:value-of select="references"/>
+                </td>
+                <td>
+                  <xsl:value-of select="state"/>
+                </td>
+                <td>
+                  <xsl:value-of select="quantum"/>
+                </td>
+                <td>
+                  <xsl:value-of select="events"/>
+                </td>
+              </tr>
+            </xsl:for-each>
+          </table>
+          <br/>
+        </xsl:if>
+        <xsl:if test="memory/summary">
+          <h2>Memory Usage Summary</h2>
+          <table class="counters">
+            <xsl:for-each select="memory/summary/*">
+              <xsl:variable name="css-class13">
+                <xsl:choose>
+                  <xsl:when test="position() mod 2 = 0">even</xsl:when>
+                  <xsl:otherwise>odd</xsl:otherwise>
+                </xsl:choose>
+              </xsl:variable>
+              <tr class="{$css-class13}">
+                <th>
+                  <xsl:value-of select="name()"/>
+                </th>
+                <td>
+                  <xsl:value-of select="."/>
+                </td>
+              </tr>
+            </xsl:for-each>
+          </table>
+          <br/>
+        </xsl:if>
+        <xsl:if test="memory/contexts/context">
+          <h2>Memory Contexts</h2>
+          <table class="mctx">
+            <tr>
+              <th>ID</th>
+              <th>Name</th>
+              <th>References</th>
+              <th>TotalUse</th>
+              <th>InUse</th>
+              <th>MaxUse</th>
+              <th>BlockSize</th>
+              <th>Pools</th>
+              <th>HiWater</th>
+              <th>LoWater</th>
+            </tr>
+            <xsl:for-each select="memory/contexts/context">
+              <xsl:sort select="total" data-type="number" order="descending"/>
+              <xsl:variable name="css-class14">
+                <xsl:choose>
+                  <xsl:when test="position() mod 2 = 0">even</xsl:when>
+                  <xsl:otherwise>odd</xsl:otherwise>
+                </xsl:choose>
+              </xsl:variable>
+              <tr class="{$css-class14}">
+                <td>
+                  <xsl:value-of select="id"/>
+                </td>
+                <td>
+                  <xsl:value-of select="name"/>
+                </td>
+                <td>
+                  <xsl:value-of select="references"/>
+                </td>
+                <td>
+                  <xsl:value-of select="total"/>
+                </td>
+                <td>
+                  <xsl:value-of select="inuse"/>
+                </td>
+                <td>
+                  <xsl:value-of select="maxinuse"/>
+                </td>
+                <td>
+                  <xsl:value-of select="blocksize"/>
+                </td>
+                <td>
+                  <xsl:value-of select="pools"/>
+                </td>
+                <td>
+                  <xsl:value-of select="hiwater"/>
+                </td>
+                <td>
+                  <xsl:value-of select="lowater"/>
+                </td>
+              </tr>
+            </xsl:for-each>
+          </table>
+        </xsl:if>
         <hr/>
         <p class="footer">Internet Systems Consortium Inc.<br/><a href="http://www.isc.org">http://www.isc.org</a></p>
       </body>
index 8f11b26dceb80b3734c63f5908c6404a3fede8c5..29098a013c12ecec8a9497f9441bd47f0304aa14 100644 (file)
@@ -32,53 +32,58 @@ static char xslmsg[] =
        " <!-- Non Mozilla specific markup -->\n"
        " <script type=\"text/javascript\" src=\"https://www.google.com/jsapi\"/>\n"
        " <script type=\"text/javascript\">\n"
-       " \n"
+       "\n"
        " google.load(\"visualization\", \"1\", {packages:[\"corechart\"]});\n"
        " google.setOnLoadCallback(loadGraphs);\n"
        "\n"
        " var graphs=[];\n"
-       " \n"
-       " function drawChart(chart_title,target,data) {\n"
+       "\n"
+       " function drawChart(chart_title,target,style,data) {\n"
        " var data = google.visualization.arrayToDataTable(data);\n"
        "\n"
        " var options = {\n"
        " title: chart_title\n"
        " };\n"
-       " \n"
-       " var chart = new google.visualization.BarChart(document.getElementById(target));\n"
+       "\n"
+       " var chart;\n"
+       " if (style == \"barchart\") {\n"
+       " chart = new google.visualization.BarChart(document.getElementById(target));\n"
        " chart.draw(data, options);\n"
+       " } else if (style == \"piechart\") {\n"
+       " chart = new google.visualization.PieChart(document.getElementById(target));\n"
+       " chart.draw(data, options);\n"
+       " }\n"
        " }\n"
-       " \n"
+       "\n"
        " function loadGraphs(){\n"
-       " //alert(\"here we are!\");\n"
        " var g;\n"
-       " \n"
-       " // Server Incoming query Types\n"
+       "\n"
        " while(g = graphs.shift()){\n"
        " // alert(\"going for: \" + g.target);\n"
        " if(g.data.length > 1){\n"
-       " drawChart(g.title,g.target,g.data);\n"
+       " drawChart(g.title,g.target,g.style,g.data);\n"
        " }\n"
        " }\n"
        " }\n"
-       " \n"
-       " // Server Incoming Queries Types \n"
+       "\n"
+       " <xsl:if test=\"server/counters[@type=&quot;qtype&quot;]/counter\">\n"
+       " // Server Incoming Query Types\n"
        " graphs.push({\n"
        " 'title' : \"Server Incoming Query Types\",\n"
        " 'target': 'chart_incoming_qtypes',\n"
+       " 'style': 'barchart',\n"
        " 'data': [['Type','Counter'],<xsl:for-each select=\"server/counters[@type=&quot;qtype&quot;]/counter\">['<xsl:value-of select=\"@name\"/>',<xsl:value-of select=\".\"/>],</xsl:for-each>]\n"
        " });\n"
+       " </xsl:if>\n"
        "\n"
-       "\n"
-       " // Server Incoming Requests \n"
+       " <xsl:if test=\"server/counters[@type=&quot;opcode&quot;]/counter\">\n"
+       " // Server Incoming Requests by opcode\n"
        " graphs.push({\n"
-       " 'title' : \"Server Incoming Requests\",\n"
-       " 'target': 'chart_incoming_requests',\n"
-       " 'data': [['Requests','Counter'],<xsl:for-each select=\"server/counters[@type=&quot;opcode&quot;]/counter\">['<xsl:value-of select=\"@name\"/>',<xsl:value-of select=\".\"/>],</xsl:for-each>]});\n"
-       " \n"
-       " \n"
-       " \n"
-       " \n"
+       " 'title' : \"Server Incoming Requests by DNS Opcode\",\n"
+       " 'target': 'chart_incoming_opcodes',\n"
+       " 'style': 'barchart',\n"
+       " 'data': [['Opcode','Counter'],<xsl:for-each select=\"server/counters[@type=&quot;opcode&quot;]/counter[. &gt; 0 or substring(@name,1,3) != 'RES']\">['<xsl:value-of select=\"@name\"/>',<xsl:value-of select=\".\"/>],</xsl:for-each>]});\n"
+       " </xsl:if>\n"
        " </script>\n"
        " </xsl:if>\n"
        " <style type=\"text/css\">\n"
@@ -88,15 +93,15 @@ static char xslmsg[] =
        " color: #000000;\n"
        " font-size: 10pt;\n"
        " }\n"
-       " \n"
+       "\n"
        " .odd{\n"
        " background-color: #f0f0f0;\n"
        " }\n"
-       " \n"
+       "\n"
        " .even{\n"
        " background-color: #ffffff;\n"
        " }\n"
-       " \n"
+       "\n"
        " p.footer{\n"
        " font-style:italic;\n"
        " color: grey;\n"
@@ -111,21 +116,101 @@ static char xslmsg[] =
        " border: 1px solid grey;\n"
        " width: 500px;\n"
        " }\n"
-       " \n"
        " table.counters th {\n"
-       " text-align: center;\n"
+       " text-align: right;\n"
        " border: 1px solid grey;\n"
-       " width: 120px;\n"
+       " width: 150px;\n"
        " }\n"
-       " table.counters td{\n"
-       " text-align:center;\n"
-       " \n"
+       " table.counters td {\n"
+       " text-align: right;\n"
+       " font-family: monospace;\n"
        " }\n"
-       " \n"
        " table.counters tr:hover{\n"
        " background-color: #99ddff;\n"
        " }\n"
-       " \n"
+       "\n"
+       " table.info {\n"
+       " border: 1px solid grey;\n"
+       " width: 500px;\n"
+       " }\n"
+       " table.info th {\n"
+       " text-align: center;\n"
+       " border: 1px solid grey;\n"
+       " width: 150px;\n"
+       " }\n"
+       " table.info td {\n"
+       " text-align: center;\n"
+       " }\n"
+       " table.info tr:hover{\n"
+       " background-color: #99ddff;\n"
+       " }\n"
+       "\n"
+       " table.tasks {\n"
+       " border: 1px solid grey;\n"
+       " width: 500px;\n"
+       " }\n"
+       " table.tasks th {\n"
+       " text-align: center;\n"
+       " border: 1px solid grey;\n"
+       " width: 150px;\n"
+       " }\n"
+       " table.tasks td {\n"
+       " text-align: right;\n"
+       " font-family: monospace;\n"
+       " }\n"
+       " table.tasks td:nth-child(2) {\n"
+       " text-align: center;\n"
+       " }\n"
+       " table.tasks td:nth-child(4) {\n"
+       " text-align: center;\n"
+       " }\n"
+       " table.tasks tr:hover{\n"
+       " background-color: #99ddff;\n"
+       " }\n"
+       "\n"
+       " table.netstat {\n"
+       " border: 1px solid grey;\n"
+       " width: 500px;\n"
+       " }\n"
+       " table.netstat th {\n"
+       " text-align: center;\n"
+       " border: 1px solid grey;\n"
+       " width: 150px;\n"
+       " }\n"
+       " table.netstat td {\n"
+       " text-align: center;\n"
+       " }\n"
+       " table.netstat td:nth-child(4) {\n"
+       " text-align: right;\n"
+       " font-family: monospace;\n"
+       " }\n"
+       " table.netstat td:nth-child(7) {\n"
+       " text-align: left;\n"
+       " }\n"
+       " table.netstat tr:hover{\n"
+       " background-color: #99ddff;\n"
+       " }\n"
+       "\n"
+       " table.mctx {\n"
+       " border: 1px solid grey;\n"
+       " width: 500px;\n"
+       " }\n"
+       " table.mctx th {\n"
+       " text-align: center;\n"
+       " border: 1px solid grey;\n"
+       " }\n"
+       " table.mctx td {\n"
+       " text-align: right;\n"
+       " font-family: monospace;\n"
+       " }\n"
+       " table.mctx td:nth-child(-n+2) {\n"
+       " text-align: left;\n"
+       " width: 100px;\n"
+       " }\n"
+       " table.mctx tr:hover{\n"
+       " background-color: #99ddff;\n"
+       " }\n"
+       "\n"
        " .totals {\n"
        " background-color: rgb(1,169,206);\n"
        " color: #ffffff;\n"
@@ -165,20 +250,18 @@ static char xslmsg[] =
        " width:500px;\n"
        " text-align:center;\n"
        " }\n"
-       " \n"
+       "\n"
        " h3 {\n"
        " color: #444444;\n"
        " font-size: 12pt;\n"
        " width:500px;\n"
        " text-align:center;\n"
-       " \n"
        " }\n"
        " h4 {\n"
        " color: rgb(1,169,206);\n"
        " font-size: 10pt;\n"
        " width:500px;\n"
        " text-align:center;\n"
-       " \n"
        " }\n"
        "\n"
        " .pie {\n"
@@ -194,8 +277,8 @@ static char xslmsg[] =
        " <h1>ISC Bind 9 Configuration and Statistics</h1>\n"
        " </div>\n"
        " <hr/>\n"
-       " <h2>Server Times</h2>\n"
-       " <table class=\"counters\">\n"
+       " <h2>Server Status</h2>\n"
+       " <table class=\"info\">\n"
        " <tr>\n"
        " <th>Boot time:</th>\n"
        " <td>\n"
@@ -216,13 +299,16 @@ static char xslmsg[] =
        " </tr>\n"
        " </table>\n"
        " <br/>\n"
-       " <h2>Incoming Requests</h2>\n"
+       " <xsl:if test=\"server/counters[@type=&quot;opcode&quot;]/counter[. &gt; 0]\">\n"
        " <xsl:if test=\"system-property('xsl:vendor')!='Transformiix'\">\n"
+       " <h2>Incoming Requests by DNS Opcode</h2>\n"
        " <!-- Non Mozilla specific markup -->\n"
-       " <div class=\"pie\" id=\"chart_incoming_requests\">[no incoming requests]</div>\n"
+       " <div class=\"pie\" id=\"chart_incoming_opcodes\">\n"
+       " [cannot display chart]\n"
+       " </div>\n"
        " </xsl:if>\n"
        " <table class=\"counters\">\n"
-       " <xsl:for-each select=\"server/counters[@type=&quot;opcode&quot;]/counter\">\n"
+       " <xsl:for-each select=\"server/counters[@type=&quot;opcode&quot;]/counter[. &gt; 0 or substring(@name,1,3) != 'RES']\">\n"
        " <xsl:sort select=\".\" data-type=\"number\" order=\"descending\"/>\n"
        " <tr>\n"
        " <th>\n"
@@ -241,10 +327,14 @@ static char xslmsg[] =
        " </tr>\n"
        " </table>\n"
        " <br/>\n"
-       " <h3>Incoming Queries by Type</h3>\n"
+       " </xsl:if>\n"
+       " <xsl:if test=\"server/counters[@type=&quot;qtype&quot;]/counter\">\n"
        " <xsl:if test=\"system-property('xsl:vendor')!='Transformiix'\">\n"
        " <!-- Non Mozilla specific markup -->\n"
-       " <div class=\"pie\" id=\"chart_incoming_qtypes\">[no incoming queries]</div>\n"
+       " <h3>Incoming Queries by Query Type</h3>\n"
+       " <div class=\"pie\" id=\"chart_incoming_qtypes\">\n"
+       " [cannot display chart]\n"
+       " </div>\n"
        " </xsl:if>\n"
        " <table class=\"counters\">\n"
        " <xsl:for-each select=\"server/counters[@type=&quot;qtype&quot;]/counter\">\n"
@@ -272,6 +362,8 @@ static char xslmsg[] =
        " </tr>\n"
        " </table>\n"
        " <br/>\n"
+       " </xsl:if>\n"
+       " <xsl:if test=\"views/view[count(counters[@type=&quot;resqtype&quot;]/counter) &gt; 0]\">\n"
        " <h2>Outgoing Queries per view</h2>\n"
        " <xsl:for-each select=\"views/view[count(counters[@type=&quot;resqtype&quot;]/counter) &gt; 0]\">\n"
        " <h3>View <xsl:value-of select=\"@name\"/></h3>\n"
@@ -279,16 +371,16 @@ static char xslmsg[] =
        " <!-- Non Mozilla specific markup -->\n"
        " <script type=\"text/javascript\">\n"
        " graphs.push({\n"
-       " 'title': \"Outgoing queries for view: <xsl:value-of select=\"@name\"/>\",\n"
+       " 'title': \"Outgoing Queries for view: <xsl:value-of select=\"@name\"/>\",\n"
        " 'target': 'chart_outgoing_queries_view_<xsl:value-of select=\"@name\"/>',\n"
+       " 'style': 'barchart',\n"
        " 'data': [['Type','Counter'],<xsl:for-each select=\"counters[@type=&quot;resqtype&quot;]/counter\">['<xsl:value-of select=\"@name\"/>',<xsl:value-of select=\".\"/>],</xsl:for-each>]\n"
        " });\n"
-       " \n"
        " </script>\n"
        " <xsl:variable name=\"target\">\n"
        " <xsl:value-of select=\"@name\"/>\n"
        " </xsl:variable>\n"
-       " <div class=\"pie\" id=\"chart_outgoing_queries_view_{$target}\"/>\n"
+       " <div class=\"pie\" id=\"chart_outgoing_queries_view_{$target}\">[no data to display]</div>\n"
        " </xsl:if>\n"
        " <table class=\"counters\">\n"
        " <xsl:for-each select=\"counters[@type=&quot;resqtype&quot;]/counter\">\n"
@@ -311,6 +403,8 @@ static char xslmsg[] =
        " </table>\n"
        " <br/>\n"
        " </xsl:for-each>\n"
+       " </xsl:if>\n"
+       " <xsl:if test=\"server/counters[@type=&quot;nsstat&quot;]/counter[.&gt;0]\">\n"
        " <h2>Server Statistics</h2>\n"
        " <xsl:if test=\"system-property('xsl:vendor')!='Transformiix'\">\n"
        " <!-- Non Mozilla specific markup -->\n"
@@ -318,11 +412,11 @@ static char xslmsg[] =
        " graphs.push({\n"
        " 'title' : \"Server Counters\",\n"
        " 'target': 'chart_server_nsstat_restype',\n"
+       " 'style': 'barchart',\n"
        " 'data': [['Type','Counter'],<xsl:for-each select=\"server/counters[@type=&quot;nsstat&quot;]/counter[.&gt;0]\">['<xsl:value-of select=\"@name\"/>',<xsl:value-of select=\".\"/>],</xsl:for-each>]\n"
        " });\n"
-       " \n"
        " </script>\n"
-       " <div class=\"pie\" id=\"chart_server_nsstat_restype\"/>\n"
+       " <div class=\"pie\" id=\"chart_server_nsstat_restype\">[no data to display]</div>\n"
        " </xsl:if>\n"
        " <table class=\"counters\">\n"
        " <xsl:for-each select=\"server/counters[@type=&quot;nsstat&quot;]/counter[.&gt;0]\">\n"
@@ -344,18 +438,20 @@ static char xslmsg[] =
        " </xsl:for-each>\n"
        " </table>\n"
        " <br/>\n"
-       " <h2>Zone Maintenance Statistics</h2>\n"
+       " </xsl:if>\n"
+       " <xsl:if test=\"server/counters[@type=&quot;zonestat&quot;]/counter[.&gt;0]\">\n"
        " <xsl:if test=\"system-property('xsl:vendor')!='Transformiix'\">\n"
+       " <h2>Zone Maintenance Statistics</h2>\n"
        " <script type=\"text/javascript\">\n"
        " graphs.push({\n"
        " 'title' : \"Zone Maintenance Stats\",\n"
        " 'target': 'chart_server_zone_maint',\n"
-       " 'data': [['Type','Counter'],<xsl:for-each select=\"server/counters[@type=&quot;zonestat&quot;]/counter\">['<xsl:value-of select=\"@name\"/>',<xsl:value-of select=\".\"/>],</xsl:for-each>]\n"
+       " 'style': 'barchart',\n"
+       " 'data': [['Type','Counter'],<xsl:for-each select=\"server/counters[@type=&quot;zonestat&quot;]/counter[.&gt;0]\">['<xsl:value-of select=\"@name\"/>',<xsl:value-of select=\".\"/>],</xsl:for-each>]\n"
        " });\n"
-       "\n"
        " </script>\n"
        " <!-- Non Mozilla specific markup -->\n"
-       " <div class=\"pie\" id=\"chart_server_zone_maint\"/>\n"
+       " <div class=\"pie\" id=\"chart_server_zone_maint\">[no data to display]</div>\n"
        " </xsl:if>\n"
        " <table class=\"counters\">\n"
        " <xsl:for-each select=\"server/counters[@type=&quot;zonestat&quot;]/counter\">\n"
@@ -376,6 +472,8 @@ static char xslmsg[] =
        " </tr>\n"
        " </xsl:for-each>\n"
        " </table>\n"
+       " </xsl:if>\n"
+       " <xsl:if test=\"server/counters[@type=&quot;resstat&quot;]/counter[.&gt;0]\">\n"
        " <h2>Resolver Statistics (Common)</h2>\n"
        " <table class=\"counters\">\n"
        " <xsl:for-each select=\"server/counters[@type=&quot;resstat&quot;]/counter\">\n"
@@ -396,7 +494,9 @@ static char xslmsg[] =
        " </tr>\n"
        " </xsl:for-each>\n"
        " </table>\n"
+       " </xsl:if>\n"
        " <xsl:for-each select=\"views/view\">\n"
+       " <xsl:if test=\"counters[@type=&quot;resstats&quot;]/counter[.&gt;0]\">\n"
        " <h3>Resolver Statistics for View <xsl:value-of select=\"@name\"/></h3>\n"
        " <table class=\"counters\">\n"
        " <xsl:for-each select=\"counters[@type=&quot;resstats&quot;]/counter[.&gt;0]\">\n"
@@ -417,10 +517,10 @@ static char xslmsg[] =
        " </tr>\n"
        " </xsl:for-each>\n"
        " </table>\n"
+       " </xsl:if>\n"
        " </xsl:for-each>\n"
-       "\n"
-       "\n"
        " <xsl:for-each select=\"views/view\">\n"
+       " <xsl:if test=\"counters[@type=&quot;adbstat&quot;]/counter[.&gt;0]\">\n"
        " <h3>ADB Statistics for View <xsl:value-of select=\"@name\"/></h3>\n"
        " <table class=\"counters\">\n"
        " <xsl:for-each select=\"counters[@type=&quot;adbstat&quot;]/counter[.&gt;0]\">\n"
@@ -441,9 +541,11 @@ static char xslmsg[] =
        " </tr>\n"
        " </xsl:for-each>\n"
        " </table>\n"
+       " </xsl:if>\n"
        " </xsl:for-each>\n"
        "\n"
        " <xsl:for-each select=\"views/view\">\n"
+       " <xsl:if test=\"counters[@type=&quot;cachestats&quot;]/counter[.&gt;0]\">\n"
        " <h3>Cache Statistics for View <xsl:value-of select=\"@name\"/></h3>\n"
        " <table class=\"counters\">\n"
        " <xsl:for-each select=\"counters[@type=&quot;cachestats&quot;]/counter[.&gt;0]\">\n"
@@ -464,11 +566,12 @@ static char xslmsg[] =
        " </tr>\n"
        " </xsl:for-each>\n"
        " </table>\n"
+       " </xsl:if>\n"
        " </xsl:for-each>\n"
        "\n"
-       "\n"
-       " <h3>Cache DB RRsets for View <xsl:value-of select=\"@name\"/></h3>\n"
        " <xsl:for-each select=\"views/view\">\n"
+       " <xsl:if test=\"cache/rrset\">\n"
+       " <h3>Cache DB RRsets for View <xsl:value-of select=\"@name\"/></h3>\n"
        " <table class=\"counters\">\n"
        " <xsl:for-each select=\"cache/rrset\">\n"
        " <xsl:variable name=\"css-class6\">\n"
@@ -488,7 +591,10 @@ static char xslmsg[] =
        " </xsl:for-each>\n"
        " </table>\n"
        " <br/>\n"
+       " </xsl:if>\n"
        " </xsl:for-each>\n"
+       "\n"
+       " <xsl:if test=\"server/counters[@type=&quot;sockstat&quot;]/counter[.&gt;0]\">\n"
        " <h2>Socket I/O Statistics</h2>\n"
        " <table class=\"counters\">\n"
        " <xsl:for-each select=\"server/counters[@type=&quot;sockstat&quot;]/counter[.&gt;0]\">\n"
@@ -509,33 +615,35 @@ static char xslmsg[] =
        " </xsl:for-each>\n"
        " </table>\n"
        " <br/>\n"
-       " <br/>\n"
-       " <h2>Response Codes per view/zone</h2>\n"
-       " <xsl:for-each select=\"views/view[zones/zone/counters[@type=&quot;rcode&quot;]/counter &gt;0]\">\n"
+       " </xsl:if>\n"
+       " <xsl:if test=\"views/view[zones/zone/counters[@type=&quot;qtype&quot;]/counter &gt;0]\">\n"
+       " <h2>Received QTYPES per view/zone</h2>\n"
+       " <xsl:for-each select=\"views/view[zones/zone/counters[@type=&quot;qtype&quot;]/counter &gt;0]\">\n"
        " <h3>View <xsl:value-of select=\"@name\"/></h3>\n"
        " <xsl:variable name=\"thisview\">\n"
        " <xsl:value-of select=\"@name\"/>\n"
        " </xsl:variable>\n"
        " <xsl:for-each select=\"zones/zone\">\n"
-       " <xsl:if test=\"counters[@type=&quot;rcode&quot;]/counter[. &gt; 0]\">\n"
+       " <xsl:if test=\"counters[@type=&quot;qtype&quot;]/counter[count(.) &gt; 0]\">\n"
        " <h4>Zone <xsl:value-of select=\"@name\"/></h4>\n"
        " <xsl:if test=\"system-property('xsl:vendor')!='Transformiix'\">\n"
        " <!-- Non Mozilla specific markup -->\n"
        " <script type=\"text/javascript\">\n"
        " graphs.push({\n"
-       " 'title': \"Response Codes for zone <xsl:value-of select=\"@name\"/>\",\n"
-       " 'target': 'chart_rescode_<xsl:value-of select=\"../../@name\"/>_<xsl:value-of select=\"@name\"/>',\n"
-       " 'data': [['Type','Counter'],<xsl:for-each select=\"counters[@type=&quot;rcode&quot;]/counter[.&gt;0 and @name != &quot;QryAuthAns&quot;]\">['<xsl:value-of select=\"@name\"/>',<xsl:value-of select=\".\"/>],</xsl:for-each>]\n"
+       " 'title': \"Query types for zone <xsl:value-of select=\"@name\"/>\",\n"
+       " 'target': 'chart_qtype_<xsl:value-of select=\"../../@name\"/>_<xsl:value-of select=\"@name\"/>',\n"
+       " 'style': 'barchart',\n"
+       " 'data': [['Type','Counter'],<xsl:for-each select=\"counters[@type=&quot;qtype&quot;]/counter[.&gt;0 and @name != &quot;QryAuthAns&quot;]\">['<xsl:value-of select=\"@name\"/>',<xsl:value-of select=\".\"/>],</xsl:for-each>]\n"
        " });\n"
        "\n"
        " </script>\n"
        " <xsl:variable name=\"target\">\n"
        " <xsl:value-of select=\"@name\"/>\n"
        " </xsl:variable>\n"
-       " <div class=\"pie\" id=\"chart_rescode_{$thisview}_{$target}\"/>\n"
+       " <div class=\"pie\" id=\"chart_qtype_{$thisview}_{$target}\">[no data to display]</div>\n"
        " </xsl:if>\n"
        " <table class=\"counters\">\n"
-       " <xsl:for-each select=\"counters[@type=&quot;rcode&quot;]/counter[.&gt;0 and @name != &quot;QryAuthAns&quot;]\">\n"
+       " <xsl:for-each select=\"counters[@type=&quot;qtype&quot;]/counter\">\n"
        " <xsl:sort select=\".\"/>\n"
        " <xsl:variable name=\"css-class10\">\n"
        " <xsl:choose>\n"
@@ -556,32 +664,35 @@ static char xslmsg[] =
        " </xsl:if>\n"
        " </xsl:for-each>\n"
        " </xsl:for-each>\n"
-       " <h2>Received QTYPES per view/zone</h2>\n"
-       " <xsl:for-each select=\"views/view[zones/zone/counters[@type=&quot;qtype&quot;]/counter &gt;0]\">\n"
+       " </xsl:if>\n"
+       " <xsl:if test=\"views/view[zones/zone/counters[@type=&quot;rcode&quot;]/counter &gt;0]\">\n"
+       " <h2>Response Codes per view/zone</h2>\n"
+       " <xsl:for-each select=\"views/view[zones/zone/counters[@type=&quot;rcode&quot;]/counter &gt;0]\">\n"
        " <h3>View <xsl:value-of select=\"@name\"/></h3>\n"
        " <xsl:variable name=\"thisview2\">\n"
        " <xsl:value-of select=\"@name\"/>\n"
        " </xsl:variable>\n"
        " <xsl:for-each select=\"zones/zone\">\n"
-       " <xsl:if test=\"counters[@type=&quot;qtype&quot;]/counter[count(.) &gt; 0]\">\n"
+       " <xsl:if test=\"counters[@type=&quot;rcode&quot;]/counter[. &gt; 0]\">\n"
        " <h4>Zone <xsl:value-of select=\"@name\"/></h4>\n"
        " <xsl:if test=\"system-property('xsl:vendor')!='Transformiix'\">\n"
        " <!-- Non Mozilla specific markup -->\n"
        " <script type=\"text/javascript\">\n"
        " graphs.push({\n"
-       " 'title': \"Query Types for zone <xsl:value-of select=\"@name\"/>\",\n"
-       " 'target': 'chart_qtype_<xsl:value-of select=\"../../@name\"/>_<xsl:value-of select=\"@name\"/>',\n"
-       " 'data': [['Type','Counter'],<xsl:for-each select=\"counters[@type=&quot;qtype&quot;]/counter[.&gt;0 and @name != &quot;QryAuthAns&quot;]\">['<xsl:value-of select=\"@name\"/>',<xsl:value-of select=\".\"/>],</xsl:for-each>]\n"
+       " 'title': \"Response codes for zone <xsl:value-of select=\"@name\"/>\",\n"
+       " 'target': 'chart_rescode_<xsl:value-of select=\"../../@name\"/>_<xsl:value-of select=\"@name\"/>',\n"
+       " 'style': 'barchart',\n"
+       " 'data': [['Type','Counter'],<xsl:for-each select=\"counters[@type=&quot;rcode&quot;]/counter[.&gt;0 and @name != &quot;QryAuthAns&quot;]\">['<xsl:value-of select=\"@name\"/>',<xsl:value-of select=\".\"/>],</xsl:for-each>]\n"
        " });\n"
        "\n"
        " </script>\n"
        " <xsl:variable name=\"target\">\n"
        " <xsl:value-of select=\"@name\"/>\n"
        " </xsl:variable>\n"
-       " <div class=\"pie\" id=\"chart_qtype_{$thisview2}_{$target}\"/>\n"
+       " <div class=\"pie\" id=\"chart_rescode_{$thisview2}_{$target}\">[no data to display]</div>\n"
        " </xsl:if>\n"
        " <table class=\"counters\">\n"
-       " <xsl:for-each select=\"counters[@type=&quot;qtype&quot;]/counter\">\n"
+       " <xsl:for-each select=\"counters[@type=&quot;rcode&quot;]/counter[.&gt;0 and @name != &quot;QryAuthAns&quot;]\">\n"
        " <xsl:sort select=\".\"/>\n"
        " <xsl:variable name=\"css-class11\">\n"
        " <xsl:choose>\n"
@@ -602,8 +713,10 @@ static char xslmsg[] =
        " </xsl:if>\n"
        " </xsl:for-each>\n"
        " </xsl:for-each>\n"
+       " </xsl:if>\n"
+       " <xsl:if test=\"socketmgr/sockets/socket\">\n"
        " <h2>Network Status</h2>\n"
-       " <table class=\"counters\">\n"
+       " <table class=\"netstat\">\n"
        " <tr>\n"
        " <th>ID</th>\n"
        " <th>Name</th>\n"
@@ -649,6 +762,8 @@ static char xslmsg[] =
        " </xsl:for-each>\n"
        " </table>\n"
        " <br/>\n"
+       " </xsl:if>\n"
+       " <xsl:if test=\"taskmgr/thread-model/type\">\n"
        " <h2>Task Manager Configuration</h2>\n"
        " <table class=\"counters\">\n"
        " <tr>\n"
@@ -675,7 +790,7 @@ static char xslmsg[] =
        " <xsl:value-of select=\"taskmgr/thread-model/tasks-running\"/>\n"
        " </td>\n"
        " </tr>\n"
-       " <tr class=\"odd\">\n"
+       " <tr class=\"even\">\n"
        " <th>Tasks Ready</th>\n"
        " <td>\n"
        " <xsl:value-of select=\"taskmgr/thread-model/tasks-ready\"/>\n"
@@ -683,8 +798,10 @@ static char xslmsg[] =
        " </tr>\n"
        " </table>\n"
        " <br/>\n"
+       " </xsl:if>\n"
+       " <xsl:if test=\"taskmgr/tasks/task\">\n"
        " <h2>Tasks</h2>\n"
-       " <table class=\"counters\">\n"
+       " <table class=\"tasks\">\n"
        " <tr>\n"
        " <th>ID</th>\n"
        " <th>Name</th>\n"
@@ -724,6 +841,8 @@ static char xslmsg[] =
        " </xsl:for-each>\n"
        " </table>\n"
        " <br/>\n"
+       " </xsl:if>\n"
+       " <xsl:if test=\"memory/summary\">\n"
        " <h2>Memory Usage Summary</h2>\n"
        " <table class=\"counters\">\n"
        " <xsl:for-each select=\"memory/summary/*\">\n"
@@ -744,8 +863,10 @@ static char xslmsg[] =
        " </xsl:for-each>\n"
        " </table>\n"
        " <br/>\n"
+       " </xsl:if>\n"
+       " <xsl:if test=\"memory/contexts/context\">\n"
        " <h2>Memory Contexts</h2>\n"
-       " <table class=\"counters\">\n"
+       " <table class=\"mctx\">\n"
        " <tr>\n"
        " <th>ID</th>\n"
        " <th>Name</th>\n"
@@ -800,6 +921,7 @@ static char xslmsg[] =
        " </tr>\n"
        " </xsl:for-each>\n"
        " </table>\n"
+       " </xsl:if>\n"
        " <hr/>\n"
        " <p class=\"footer\">Internet Systems Consortium Inc.<br/><a href=\"http://www.isc.org\">http://www.isc.org</a></p>\n"
        " </body>\n"
index f3553685be39a65a009ca1a0c6518e082cc8c114..9d0087f68f9d256c541afdac632fbcdf648f6e27 100755 (executable)
@@ -37,6 +37,7 @@ while (<>) {
     s/\>\ \</\>\</g;
     s/\"/\\\"/g;
     s/^/\t\"/;
+    s/[\ \t]+$//g;
     s/$/\\n\"/;
     if ($lines eq "") {
            $lines .= $_;
index 22e3b4d5904bf2972c3c81c9cf14442de1793562..9c8f1437afe74d8a9edf92b3e0c80cbab1aee00f 100644 (file)
@@ -8779,6 +8779,9 @@ ns_server_add_zone(ns_server_t *server, char *args) {
                                  "zone %s added to view %s via addzone",
                                  zonename, viewname);
 
+       /* Adding a zone counts as reconfiguration */
+       CHECK(isc_time_now(&ns_g_configtime));
+
        result = ISC_R_SUCCESS;
 
  cleanup:
@@ -9038,6 +9041,9 @@ ns_server_del_zone(ns_server_t *server, char *args, isc_buffer_t *text) {
                                  NS_LOGMODULE_SERVER, ISC_LOG_INFO,
                                  "zone %s removed via delzone", zonename);
 
+       /* Removing a zone counts as reconfiguration */
+       CHECK(isc_time_now(&ns_g_configtime));
+
        result = ISC_R_SUCCESS;
 
  cleanup:
index d3c74f937f1fea9273ebe63390d40f2028a36bdc..9cefff6d036e1279182d452ee1f38030e857748c 100644 (file)
@@ -856,8 +856,16 @@ opcodestat_dump(dns_opcode_t code, isc_uint64_t val, void *arg) {
 }
 
 #ifdef HAVE_LIBXML2
-
-/* XXXMLG below here sucks. (not so much) */
+/*
+ * Which statistics to include when rendering to XML
+ */
+#define STATS_XML_STATUS       0x00    /* display only common statistics */
+#define STATS_XML_SERVER       0x01
+#define STATS_XML_ZONES                0x02
+#define STATS_XML_TASKS                0x04
+#define STATS_XML_NET          0x08
+#define STATS_XML_MEM          0x10
+#define STATS_XML_ALL          0xff
 
 static isc_result_t
 zone_xmlrender(dns_zone_t *zone, void *arg) {
@@ -943,7 +951,9 @@ zone_xmlrender(dns_zone_t *zone, void *arg) {
 }
 
 static isc_result_t
-generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
+generatexml(ns_server_t *server, isc_uint32_t flags,
+           int *buflen, xmlChar **buf)
+{
        char boottime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
        char configtime[sizeof "yyyy-mm-ddThh:mm:ssZ"];
        char nowstr[sizeof "yyyy-mm-ddThh:mm:ssZ"];
@@ -974,29 +984,139 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
                        ISC_XMLCHAR "type=\"text/xsl\" href=\"/bind9.xsl\""));
        TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics"));
        TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version",
-                                        ISC_XMLCHAR "3.1"));
+                                        ISC_XMLCHAR "3.4"));
 
        /* Set common fields for statistics dump */
        dumparg.type = isc_statsformat_xml;
        dumparg.arg = writer;
 
+       /* Render server information */
+       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server"));
+       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time"));
+       TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime));
+       TRY0(xmlTextWriterEndElement(writer)); /* boot-time */
+       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "config-time"));
+       TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR configtime));
+       TRY0(xmlTextWriterEndElement(writer)); /* config-time */
+       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time"));
+       TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr));
+       TRY0(xmlTextWriterEndElement(writer));  /* current-time */
+
+       if ((flags & STATS_XML_SERVER) != 0) {
+               dumparg.result = ISC_R_SUCCESS;
+
+               TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
+               TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
+                                                ISC_XMLCHAR "opcode"));
+
+               dns_opcodestats_dump(server->opcodestats, opcodestat_dump,
+                                    &dumparg, ISC_STATSDUMP_VERBOSE);
+               if (dumparg.result != ISC_R_SUCCESS)
+                       goto error;
+
+               TRY0(xmlTextWriterEndElement(writer));
+
+               TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
+               TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
+                                                ISC_XMLCHAR "qtype"));
+
+               dumparg.result = ISC_R_SUCCESS;
+               dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump,
+                                       &dumparg, 0);
+               if (dumparg.result != ISC_R_SUCCESS)
+                       goto error;
+               TRY0(xmlTextWriterEndElement(writer)); /* counters */
+
+               TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
+               TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
+                                                ISC_XMLCHAR "nsstat"));
+
+               result = dump_counters(server->nsstats, isc_statsformat_xml,
+                                      writer, NULL, nsstats_xmldesc,
+                                      dns_nsstatscounter_max,
+                                      nsstats_index, nsstat_values,
+                                      ISC_STATSDUMP_VERBOSE);
+               if (result != ISC_R_SUCCESS)
+                       goto error;
+
+               TRY0(xmlTextWriterEndElement(writer)); /* /nsstat */
+
+               TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
+               TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
+                                                ISC_XMLCHAR "zonestat"));
+
+               result = dump_counters(server->zonestats, isc_statsformat_xml,
+                                      writer, NULL, zonestats_xmldesc,
+                                      dns_zonestatscounter_max,
+                                      zonestats_index, zonestat_values,
+                                      ISC_STATSDUMP_VERBOSE);
+               if (result != ISC_R_SUCCESS)
+                       goto error;
+
+               TRY0(xmlTextWriterEndElement(writer)); /* /zonestat */
+
+               /*
+                * Most of the common resolver statistics entries are 0, so
+                * we don't use the verbose dump here.
+                */
+               TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
+               TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
+                                                ISC_XMLCHAR "resstat"));
+               result = dump_counters(server->resolverstats,
+                                      isc_statsformat_xml, writer,
+                                      NULL, resstats_xmldesc,
+                                      dns_resstatscounter_max,
+                                      resstats_index, resstat_values, 0);
+               if (result != ISC_R_SUCCESS)
+                       goto error;
+               TRY0(xmlTextWriterEndElement(writer)); /* resstat */
+       }
+
+       if ((flags & STATS_XML_NET) != 0) {
+               TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
+               TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
+                                                ISC_XMLCHAR "sockstat"));
+
+               result = dump_counters(server->sockstats, isc_statsformat_xml,
+                                      writer, NULL, sockstats_xmldesc,
+                                      isc_sockstatscounter_max,
+                                      sockstats_index, sockstat_values,
+                                      ISC_STATSDUMP_VERBOSE);
+               if (result != ISC_R_SUCCESS)
+                       goto error;
+
+               TRY0(xmlTextWriterEndElement(writer)); /* /sockstat */
+       }
+       TRY0(xmlTextWriterEndElement(writer)); /* /server */
+
        /*
-        * Start by rendering the views we know of here.  For each view we
-        * know of, call its rendering function.
+        * Render views.  For each view we know of, call its
+        * rendering function.
         */
        view = ISC_LIST_HEAD(server->viewlist);
        TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "views"));
-       while (view != NULL) {
+       while (view != NULL &&
+              ((flags & (STATS_XML_SERVER | STATS_XML_ZONES)) != 0))
+       {
                TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "view"));
                TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
                                                 ISC_XMLCHAR view->name));
 
-               TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "zones"));
-               result = dns_zt_apply(view->zonetable, ISC_TRUE, zone_xmlrender,
-                                     writer);
-               if (result != ISC_R_SUCCESS)
-                       goto error;
-               TRY0(xmlTextWriterEndElement(writer)); /* zones */
+               if ((flags & STATS_XML_ZONES) != 0) {
+                       TRY0(xmlTextWriterStartElement(writer,
+                                                      ISC_XMLCHAR "zones"));
+                       result = dns_zt_apply(view->zonetable, ISC_TRUE,
+                                             zone_xmlrender, writer);
+                       if (result != ISC_R_SUCCESS)
+                               goto error;
+                       TRY0(xmlTextWriterEndElement(writer)); /* /zones */
+               }
+
+               if ((flags & STATS_XML_SERVER) == 0) {
+                       TRY0(xmlTextWriterEndElement(writer)); /* /view */
+                       view = ISC_LIST_NEXT(view, link);
+                       continue;
+               }
 
                TRY0(xmlTextWriterStartElement(writer,
                                               ISC_XMLCHAR "counters"));
@@ -1071,115 +1191,28 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
 
                view = ISC_LIST_NEXT(view, link);
        }
-       TRY0(xmlTextWriterEndElement(writer)); /* views */
-
-       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "socketmgr"));
-       TRY0(isc_socketmgr_renderxml(ns_g_socketmgr, writer));
-       TRY0(xmlTextWriterEndElement(writer)); /* socketmgr */
-
-       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "taskmgr"));
-       TRY0(isc_taskmgr_renderxml(ns_g_taskmgr, writer));
-       TRY0(xmlTextWriterEndElement(writer)); /* taskmgr */
-
-       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "server"));
-       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "boot-time"));
-       TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR boottime));
-       TRY0(xmlTextWriterEndElement(writer)); /* boot-time */
-       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "config-time"));
-       TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR configtime));
-       TRY0(xmlTextWriterEndElement(writer)); /* config-time */
-       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "current-time"));
-       TRY0(xmlTextWriterWriteString(writer, ISC_XMLCHAR nowstr));
-       TRY0(xmlTextWriterEndElement(writer));  /* current-time */
-
-       dumparg.result = ISC_R_SUCCESS;
-
-       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
-       TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
-                                        ISC_XMLCHAR "opcode"));
-
-       dns_opcodestats_dump(server->opcodestats, opcodestat_dump, &dumparg,
-                            0);
-       if (dumparg.result != ISC_R_SUCCESS)
-               goto error;
-
-       TRY0(xmlTextWriterEndElement(writer)); /* counters type=opcode */
+       TRY0(xmlTextWriterEndElement(writer)); /* /views */
 
-       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
-       TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
-                                        ISC_XMLCHAR "qtype"));
-
-       dumparg.result = ISC_R_SUCCESS;
-       dns_rdatatypestats_dump(server->rcvquerystats, rdtypestat_dump,
-                               &dumparg, 0);
-       if (dumparg.result != ISC_R_SUCCESS)
-               goto error;
-       TRY0(xmlTextWriterEndElement(writer)); /* counters */
-
-       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
-       TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
-                                        ISC_XMLCHAR "nsstat"));
-
-       result = dump_counters(server->nsstats, isc_statsformat_xml,
-                              writer, NULL, nsstats_xmldesc,
-                              dns_nsstatscounter_max,
-                              nsstats_index, nsstat_values,
-                              ISC_STATSDUMP_VERBOSE);
-       if (result != ISC_R_SUCCESS)
-               goto error;
-
-       TRY0(xmlTextWriterEndElement(writer)); /* counters type=nsstat */
-
-       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
-       TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
-                                        ISC_XMLCHAR "zonestat"));
-
-       result = dump_counters(server->zonestats, isc_statsformat_xml, writer,
-                              NULL, zonestats_xmldesc,
-                              dns_zonestatscounter_max, zonestats_index,
-                              zonestat_values, ISC_STATSDUMP_VERBOSE);
-       if (result != ISC_R_SUCCESS)
-               goto error;
-
-       TRY0(xmlTextWriterEndElement(writer)); /* counters type=zonestat */
-
-       /*
-        * Most of the common resolver statistics entries are 0, so we don't
-        * use the verbose dump here.
-        */
-
-       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
-       TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
-                                        ISC_XMLCHAR "resstat"));
-       result = dump_counters(server->resolverstats, isc_statsformat_xml,
-                              writer, NULL, resstats_xmldesc,
-                              dns_resstatscounter_max, resstats_index,
-                              resstat_values, 0);
-       if (result != ISC_R_SUCCESS)
-               goto error;
-       TRY0(xmlTextWriterEndElement(writer)); /* counters type=resstat */
-
-       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
-       TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
-                                        ISC_XMLCHAR "sockstat"));
-
-       result = dump_counters(server->sockstats, isc_statsformat_xml,
-                              writer, NULL, sockstats_xmldesc,
-                              isc_sockstatscounter_max, sockstats_index,
-                              sockstat_values, ISC_STATSDUMP_VERBOSE);
-       if (result != ISC_R_SUCCESS)
-               goto error;
-
-       TRY0(xmlTextWriterEndElement(writer)); /* counters type=sockstat */
-
-       TRY0(xmlTextWriterEndElement(writer)); /* server */
+       if ((flags & STATS_XML_NET) != 0) {
+               TRY0(xmlTextWriterStartElement(writer,
+                                              ISC_XMLCHAR "socketmgr"));
+               TRY0(isc_socketmgr_renderxml(ns_g_socketmgr, writer));
+               TRY0(xmlTextWriterEndElement(writer)); /* /socketmgr */
+       }
 
-       TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory"));
-       TRY0(isc_mem_renderxml(writer));
-       TRY0(xmlTextWriterEndElement(writer)); /* memory */
+       if ((flags & STATS_XML_TASKS) != 0) {
+               TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "taskmgr"));
+               TRY0(isc_taskmgr_renderxml(ns_g_taskmgr, writer));
+               TRY0(xmlTextWriterEndElement(writer)); /* /taskmgr */
+       }
 
-       TRY0(xmlTextWriterEndElement(writer)); /* statistics */
+       if ((flags & STATS_XML_MEM) != 0) {
+               TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "memory"));
+               TRY0(isc_mem_renderxml(writer));
+               TRY0(xmlTextWriterEndElement(writer)); /* /memory */
+       }
 
+       TRY0(xmlTextWriterEndElement(writer)); /* /statistics */
        TRY0(xmlTextWriterEndDocument(writer));
 
        xmlFreeTextWriter(writer);
@@ -1208,10 +1241,11 @@ wrap_xmlfree(isc_buffer_t *buffer, void *arg) {
 }
 
 static isc_result_t
-render_index(const char *url, const char *querystring, void *arg,
-            unsigned int *retcode, const char **retmsg, const char **mimetype,
-            isc_buffer_t *b, isc_httpdfree_t **freecb,
-            void **freecb_args)
+render_xml(isc_uint32_t flags, const char *url, isc_httpdurl_t *urlinfo,
+          const char *querystring, const char *headers, void *arg,
+          unsigned int *retcode, const char **retmsg,
+          const char **mimetype, isc_buffer_t *b,
+          isc_httpdfree_t **freecb, void **freecb_args)
 {
        unsigned char *msg = NULL;
        int msglen;
@@ -1219,9 +1253,11 @@ render_index(const char *url, const char *querystring, void *arg,
        isc_result_t result;
 
        UNUSED(url);
+       UNUSED(urlinfo);
+       UNUSED(headers);
        UNUSED(querystring);
 
-       result = generatexml(server, &msglen, &msg);
+       result = generatexml(server, flags, &msglen, &msg);
 
        if (result == ISC_R_SUCCESS) {
                *retcode = 200;
@@ -1239,12 +1275,104 @@ render_index(const char *url, const char *querystring, void *arg,
        return (result);
 }
 
+static isc_result_t
+render_xml_all(const char *url, isc_httpdurl_t *urlinfo,
+              const char *querystring, const char *headers, void *arg,
+              unsigned int *retcode, const char **retmsg,
+              const char **mimetype, isc_buffer_t *b,
+              isc_httpdfree_t **freecb, void **freecb_args)
+{
+       return (render_xml(STATS_XML_ALL, url, urlinfo,
+                          querystring, headers, arg,
+                          retcode, retmsg, mimetype, b,
+                          freecb, freecb_args));
+}
+
+static isc_result_t
+render_xml_status(const char *url, isc_httpdurl_t *urlinfo,
+                 const char *querystring, const char *headers, void *arg,
+                 unsigned int *retcode, const char **retmsg,
+                 const char **mimetype, isc_buffer_t *b,
+                 isc_httpdfree_t **freecb, void **freecb_args)
+{
+       return (render_xml(STATS_XML_STATUS, url, urlinfo,
+                          querystring, headers, arg,
+                          retcode, retmsg, mimetype, b,
+                          freecb, freecb_args));
+}
+
+static isc_result_t
+render_xml_server(const char *url, isc_httpdurl_t *urlinfo,
+                 const char *querystring, const char *headers, void *arg,
+                 unsigned int *retcode, const char **retmsg,
+                 const char **mimetype, isc_buffer_t *b,
+                 isc_httpdfree_t **freecb, void **freecb_args)
+{
+       return (render_xml(STATS_XML_SERVER, url, urlinfo,
+                          querystring, headers, arg,
+                          retcode, retmsg, mimetype, b,
+                          freecb, freecb_args));
+}
+
+static isc_result_t
+render_xml_zones(const char *url, isc_httpdurl_t *urlinfo,
+                const char *querystring, const char *headers, void *arg,
+                unsigned int *retcode, const char **retmsg,
+                const char **mimetype, isc_buffer_t *b,
+                isc_httpdfree_t **freecb, void **freecb_args)
+{
+       return (render_xml(STATS_XML_ZONES, url, urlinfo,
+                          querystring, headers, arg,
+                          retcode, retmsg, mimetype, b,
+                          freecb, freecb_args));
+}
+
+static isc_result_t
+render_xml_net(const char *url, isc_httpdurl_t *urlinfo,
+              const char *querystring, const char *headers, void *arg,
+              unsigned int *retcode, const char **retmsg,
+              const char **mimetype, isc_buffer_t *b,
+              isc_httpdfree_t **freecb, void **freecb_args)
+{
+       return (render_xml(STATS_XML_NET, url, urlinfo,
+                          querystring, headers, arg,
+                          retcode, retmsg, mimetype, b,
+                          freecb, freecb_args));
+}
+
+static isc_result_t
+render_xml_tasks(const char *url, isc_httpdurl_t *urlinfo,
+                const char *querystring, const char *headers, void *arg,
+                unsigned int *retcode, const char **retmsg,
+                const char **mimetype, isc_buffer_t *b,
+                isc_httpdfree_t **freecb, void **freecb_args)
+{
+       return (render_xml(STATS_XML_TASKS, url, urlinfo,
+                          querystring, headers, arg,
+                          retcode, retmsg, mimetype, b,
+                          freecb, freecb_args));
+}
+
+static isc_result_t
+render_xml_mem(const char *url, isc_httpdurl_t *urlinfo,
+              const char *querystring, const char *headers, void *arg,
+              unsigned int *retcode, const char **retmsg,
+              const char **mimetype, isc_buffer_t *b,
+              isc_httpdfree_t **freecb, void **freecb_args)
+{
+       return (render_xml(STATS_XML_MEM, url, urlinfo,
+                          querystring, headers, arg,
+                          retcode, retmsg, mimetype, b,
+                          freecb, freecb_args));
+}
+
 #endif /* HAVE_LIBXML2 */
 
 #ifdef HAVE_JSON
 /*
  * Which statistics to include when rendering to JSON
  */
+#define STATS_JSON_STATUS      0x00    /* display only common statistics */
 #define STATS_JSON_SERVER      0x01
 #define STATS_JSON_ZONES       0x02
 #define STATS_JSON_TASKS       0x04
@@ -1372,7 +1500,7 @@ zone_jsonrender(dns_zone_t *zone, void *arg) {
 
 static isc_result_t
 generatejson(ns_server_t *server, size_t *msglen,
-            const char **msg, json_object **rootp, isc_uint8_t flags)
+            const char **msg, json_object **rootp, isc_uint32_t flags)
 {
        dns_view_t *view;
        isc_result_t result = ISC_R_SUCCESS;
@@ -1431,7 +1559,8 @@ generatejson(ns_server_t *server, size_t *msglen,
                dumparg.arg = counters;
 
                dns_opcodestats_dump(server->opcodestats,
-                                    opcodestat_dump, &dumparg, 0);
+                                    opcodestat_dump, &dumparg,
+                                    ISC_STATSDUMP_VERBOSE);
                if (dumparg.result != ISC_R_SUCCESS) {
                        json_object_put(counters);
                        goto error;
@@ -1745,7 +1874,9 @@ generatejson(ns_server_t *server, size_t *msglen,
 }
 
 static isc_result_t
-render_json(isc_uint8_t flags, const char *url, const char *querystring,
+render_json(isc_uint32_t flags,
+           const char *url, isc_httpdurl_t *urlinfo,
+           const char *querystring, const char *headers,
            void *arg, unsigned int *retcode, const char **retmsg,
            const char **mimetype, isc_buffer_t *b,
            isc_httpdfree_t **freecb, void **freecb_args)
@@ -1758,6 +1889,8 @@ render_json(isc_uint8_t flags, const char *url, const char *querystring,
        char *p;
 
        UNUSED(url);
+       UNUSED(urlinfo);
+       UNUSED(headers);
        UNUSED(querystring);
 
        result = generatejson(server, &msglen, &msg, &bindstats, flags);
@@ -1779,88 +1912,147 @@ render_json(isc_uint8_t flags, const char *url, const char *querystring,
 }
 
 static isc_result_t
-render_json_all(const char *url, const char *querystring, void *arg,
+render_json_all(const char *url, isc_httpdurl_t *urlinfo,
+               const char *querystring, const char *headers, void *arg,
                unsigned int *retcode, const char **retmsg,
                const char **mimetype, isc_buffer_t *b,
                isc_httpdfree_t **freecb, void **freecb_args)
 {
-       return (render_json(STATS_JSON_ALL, url, querystring, arg,
+       return (render_json(STATS_JSON_ALL, url, urlinfo,
+                           querystring, headers, arg,
                            retcode, retmsg, mimetype, b,
                            freecb, freecb_args));
 }
 
 static isc_result_t
-render_json_server(const char *url, const char *querystring, void *arg,
+render_json_status(const char *url, isc_httpdurl_t *urlinfo,
+                  const char *querystring, const char *headers, void *arg,
                   unsigned int *retcode, const char **retmsg,
                   const char **mimetype, isc_buffer_t *b,
                   isc_httpdfree_t **freecb, void **freecb_args)
 {
-       return (render_json(STATS_JSON_SERVER, url, querystring, arg,
+       return (render_json(STATS_JSON_STATUS, url, urlinfo,
+                           querystring, headers, arg,
                            retcode, retmsg, mimetype, b,
                            freecb, freecb_args));
 }
 
 static isc_result_t
-render_json_zones(const char *url, const char *querystring, void *arg,
+render_json_server(const char *url, isc_httpdurl_t *urlinfo,
+                  const char *querystring, const char *headers, void *arg,
+                  unsigned int *retcode, const char **retmsg,
+                  const char **mimetype, isc_buffer_t *b,
+                  isc_httpdfree_t **freecb, void **freecb_args)
+{
+       return (render_json(STATS_JSON_SERVER, url, urlinfo,
+                           querystring, headers, arg,
+                           retcode, retmsg, mimetype, b,
+                           freecb, freecb_args));
+}
+
+static isc_result_t
+render_json_zones(const char *url, isc_httpdurl_t *urlinfo,
+                 const char *querystring, const char *headers, void *arg,
                  unsigned int *retcode, const char **retmsg,
                  const char **mimetype, isc_buffer_t *b,
                  isc_httpdfree_t **freecb, void **freecb_args)
 {
-       return (render_json(STATS_JSON_ZONES, url, querystring, arg,
+       return (render_json(STATS_JSON_ZONES, url, urlinfo,
+                           querystring, headers, arg,
                            retcode, retmsg, mimetype, b,
                            freecb, freecb_args));
 }
 static isc_result_t
-render_json_mem(const char *url, const char *querystring, void *arg,
+render_json_mem(const char *url, isc_httpdurl_t *urlinfo,
+               const char *querystring, const char *headers, void *arg,
                unsigned int *retcode, const char **retmsg,
                const char **mimetype, isc_buffer_t *b,
                isc_httpdfree_t **freecb, void **freecb_args)
 {
-       return (render_json(STATS_JSON_MEM, url, querystring, arg,
+       return (render_json(STATS_JSON_MEM, url, urlinfo,
+                           querystring, headers, arg,
                            retcode, retmsg, mimetype, b,
                            freecb, freecb_args));
 }
 
 static isc_result_t
-render_json_tasks(const char *url, const char *querystring, void *arg,
+render_json_tasks(const char *url, isc_httpdurl_t *urlinfo,
+                 const char *querystring, const char *headers, void *arg,
                  unsigned int *retcode, const char **retmsg,
                  const char **mimetype, isc_buffer_t *b,
                  isc_httpdfree_t **freecb, void **freecb_args)
 {
-       return (render_json(STATS_JSON_TASKS, url, querystring, arg,
+       return (render_json(STATS_JSON_TASKS, url, urlinfo,
+                           querystring, headers, arg,
                            retcode, retmsg, mimetype, b,
                            freecb, freecb_args));
 }
 
 static isc_result_t
-render_json_net(const char *url, const char *querystring, void *arg,
+render_json_net(const char *url, isc_httpdurl_t *urlinfo,
+               const char *querystring, const char *headers, void *arg,
                unsigned int *retcode, const char **retmsg,
                const char **mimetype, isc_buffer_t *b,
                isc_httpdfree_t **freecb, void **freecb_args)
 {
-       return (render_json(STATS_JSON_NET, url, querystring, arg,
+       return (render_json(STATS_JSON_NET, url, urlinfo,
+                           querystring, headers, arg,
                            retcode, retmsg, mimetype, b,
                            freecb, freecb_args));
 }
 #endif /* HAVE_JSON */
 
 static isc_result_t
-render_xsl(const char *url, const char *querystring, void *args,
-          unsigned int *retcode, const char **retmsg, const char **mimetype,
-          isc_buffer_t *b, isc_httpdfree_t **freecb,
-          void **freecb_args)
+render_xsl(const char *url, isc_httpdurl_t *urlinfo,
+          const char *querystring, const char *headers,
+          void *args, unsigned int *retcode, const char **retmsg,
+          const char **mimetype, isc_buffer_t *b,
+          isc_httpdfree_t **freecb, void **freecb_args)
 {
+       isc_result_t result;
+
        UNUSED(url);
        UNUSED(querystring);
        UNUSED(args);
 
+       *freecb = NULL;
+       *freecb_args = NULL;
+       *mimetype = "text/xslt+xml";
+
+       if (urlinfo->isstatic) {
+               isc_time_t when;
+               char *p = strcasestr(headers, "If-Modified-Since: ");
+
+               if (p != NULL) {
+                       time_t t1, t2;
+                       p += strlen("If-Modified-Since: ");
+                       result = isc_time_parsehttptimestamp(p, &when);
+                       if (result != ISC_R_SUCCESS)
+                               goto send;
+
+                       result = isc_time_secondsastimet(&when, &t1);
+                       if (result != ISC_R_SUCCESS)
+                               goto send;
+
+                       result = isc_time_secondsastimet(&urlinfo->loadtime,
+                                                        &t2);
+                       if (result != ISC_R_SUCCESS)
+                               goto send;
+
+                       if (t1 < t2)
+                               goto send;
+
+                       *retcode = 304;
+                       *retmsg = "Not modified";
+                       return (ISC_R_SUCCESS);
+               }
+       }
+
+ send:
        *retcode = 200;
        *retmsg = "OK";
-       *mimetype = "text/xslt+xml";
        isc_buffer_reinit(b, xslmsg, strlen(xslmsg));
        isc_buffer_add(b, strlen(xslmsg));
-       *freecb = NULL;
-       *freecb_args = NULL;
 
        return (ISC_R_SUCCESS);
 }
@@ -1986,27 +2178,45 @@ add_listener(ns_server_t *server, ns_statschannel_t **listenerp,
                goto cleanup;
 
 #ifdef HAVE_LIBXML2
-       isc_httpdmgr_addurl(listener->httpdmgr, "/", render_index, server);
-       isc_httpdmgr_addurl(listener->httpdmgr, "/xml", render_index, server);
-       isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3", render_index,
-                           server);
+       isc_httpdmgr_addurl(listener->httpdmgr, "/",
+                           render_xml_all, server);
+       isc_httpdmgr_addurl(listener->httpdmgr, "/xml",
+                           render_xml_all, server);
+       isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3",
+                           render_xml_all, server);
+       isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/status",
+                           render_xml_status, server);
+       isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/server",
+                           render_xml_server, server);
+       isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/zones",
+                           render_xml_zones, server);
+       isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/net",
+                           render_xml_net, server);
+       isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/tasks",
+                           render_xml_tasks, server);
+       isc_httpdmgr_addurl(listener->httpdmgr, "/xml/v3/mem",
+                           render_xml_mem, server);
 #endif
 #ifdef HAVE_JSON
        isc_httpdmgr_addurl(listener->httpdmgr, "/json",
                            render_json_all, server);
-       isc_httpdmgr_addurl(listener->httpdmgr, "/json/server",
+       isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1",
+                           render_json_all, server);
+       isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/status",
+                           render_json_status, server);
+       isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/server",
                            render_json_server, server);
-       isc_httpdmgr_addurl(listener->httpdmgr, "/json/zones",
+       isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/zones",
                            render_json_zones, server);
-       isc_httpdmgr_addurl(listener->httpdmgr, "/json/tasks",
+       isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/tasks",
                            render_json_tasks, server);
-       isc_httpdmgr_addurl(listener->httpdmgr, "/json/net",
+       isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/net",
                            render_json_net, server);
-       isc_httpdmgr_addurl(listener->httpdmgr, "/json/mem",
+       isc_httpdmgr_addurl(listener->httpdmgr, "/json/v1/mem",
                            render_json_mem, server);
 #endif
-       isc_httpdmgr_addurl(listener->httpdmgr, "/bind9.xsl", render_xsl,
-                           server);
+       isc_httpdmgr_addurl2(listener->httpdmgr, "/bind9.xsl", ISC_TRUE,
+                            render_xsl, server);
 
        *listenerp = listener;
        isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
index fe6a3511b5d7b3725cf126d1766b2e81dc12d1ff..fe568d68a8af2c3dc98f9769414cffc2aa9fe482 100644 (file)
@@ -10256,25 +10256,50 @@ example.com                 CNAME   rpz-tcp-only.
           error.
         </para>
 
+        <para>
+          Broken-out subsets of the statistics can be viewed at
+          <ulink url="http://127.0.0.1:8888/xml/v3/status"
+                  >http://127.0.0.1:8888/xml/v3/status</ulink>
+          (server uptime and last reconfiguration time),
+          <ulink url="http://127.0.0.1:8888/xml/v3/server"
+                  >http://127.0.0.1:8888/xml/v3/server</ulink>
+          (server and resolver statistics),
+          <ulink url="http://127.0.0.1:8888/xml/v3/zones"
+                  >http://127.0.0.1:8888/xml/v3/zones</ulink>
+          (zone statistics),
+          <ulink url="http://127.0.0.1:8888/xml/v3/net"
+                  >http://127.0.0.1:8888/xml/v3/net</ulink>
+          (network status and socket statistics),
+          <ulink url="http://127.0.0.1:8888/xml/v3/mem"
+                  >http://127.0.0.1:8888/xml/v3/mem</ulink>
+          (memory manager statistics),
+          <ulink url="http://127.0.0.1:8888/xml/v3/tasks"
+                  >http://127.0.0.1:8888/xml/v3/tasks</ulink>
+          (task manager statistics).
+        </para>
+
         <para>
           The full set of statistics can also be read in JSON format at
           <ulink url="http://127.0.0.1:8888/json"
-                  >http://127.0.0.1:8888/json</ulink>.
-          Broken-out subsets of the statistics can be viewed at
-          <ulink url="http://127.0.0.1:8888/json/server"
-                  >http://127.0.0.1:8888/json/server</ulink>
+                  >http://127.0.0.1:8888/json</ulink>,
+          with the broken-out subsets at
+          <ulink url="http://127.0.0.1:8888/json/v1/status"
+                  >http://127.0.0.1:8888/json/v1/status</ulink>
+          (server uptime and last reconfiguration time),
+          <ulink url="http://127.0.0.1:8888/json/v1/server"
+                  >http://127.0.0.1:8888/json/v1/server</ulink>
           (server and resolver statistics),
-          <ulink url="http://127.0.0.1:8888/json/zones"
-                  >http://127.0.0.1:8888/json/zones</ulink>
+          <ulink url="http://127.0.0.1:8888/json/v1/zones"
+                  >http://127.0.0.1:8888/json/v1/zones</ulink>
           (zone statistics),
-          <ulink url="http://127.0.0.1:8888/json/net"
-                  >http://127.0.0.1:8888/json/net</ulink>
+          <ulink url="http://127.0.0.1:8888/json/v1/net"
+                  >http://127.0.0.1:8888/json/v1/net</ulink>
           (network status and socket statistics),
-          <ulink url="http://127.0.0.1:8888/json/mem"
-                  >http://127.0.0.1:8888/json/mem</ulink>
+          <ulink url="http://127.0.0.1:8888/json/v1/mem"
+                  >http://127.0.0.1:8888/json/v1/mem</ulink>
           (memory manager statistics),
-          <ulink url="http://127.0.0.1:8888/json/tasks"
-                  >http://127.0.0.1:8888/json/tasks</ulink>
+          <ulink url="http://127.0.0.1:8888/json/v1/tasks"
+                  >http://127.0.0.1:8888/json/v1/tasks</ulink>
           (task manager statistics).
         </para>
       </sect2>
index cf2b0196743e49e84a2b0c25c857153aa70be05f..24a0f8c0285823dc750a3c7db58e5c38e9c356e4 100644 (file)
@@ -26,6 +26,7 @@
 #include <isc/socket.h>
 #include <isc/string.h>
 #include <isc/task.h>
+#include <isc/time.h>
 #include <isc/util.h>
 
 #include <string.h>
 #define HTTP_SENDGROW                  1024
 #define HTTP_SEND_MAXLEN               10240
 
-/*%
- * HTTP urls.  These are the URLs we manage, and the function to call to
- * provide the data for it.  We pass in the base url (so the same function
- * can handle multiple requests), and a structure to fill in to return a
- * result to the client.  We also pass in a pointer to be filled in for
- * the data cleanup function.
- */
-struct isc_httpdurl {
-       char                           *url;
-       isc_httpdaction_t              *action;
-       void                           *action_arg;
-       ISC_LINK(isc_httpdurl_t)        link;
-};
-
 #define HTTPD_CLOSE            0x0001 /* Got a Connection: close header */
 #define HTTPD_FOUNDHOST                0x0002 /* Got a Host: header */
 
@@ -87,6 +74,7 @@ struct isc_httpd {
         */
        char                    recvbuf[HTTP_RECVLEN]; /*%< receive buffer */
        isc_uint32_t            recvlen;        /*%< length recv'd */
+       char                   *headers;        /*%< set in process_request() */
        unsigned int            method;
        char                   *url;
        char                   *querystring;
@@ -217,20 +205,12 @@ static isc_result_t process_request(isc_httpd_t *, int);
 static void httpdmgr_destroy(isc_httpdmgr_t *);
 static isc_result_t grow_headerspace(isc_httpd_t *);
 static void reset_client(isc_httpd_t *httpd);
-static isc_result_t render_404(const char *, const char *,
-                              void *,
-                              unsigned int *, const char **,
-                              const char **, isc_buffer_t *,
-                              isc_httpdfree_t **, void **);
-static isc_result_t render_500(const char *, const char *,
-                              void *,
-                              unsigned int *, const char **,
-                              const char **, isc_buffer_t *,
-                              isc_httpdfree_t **, void **);
+
+static isc_httpdaction_t render_404;
+static isc_httpdaction_t render_500;
 
 static void
-destroy_client(isc_httpd_t **httpdp)
-{
+destroy_client(isc_httpd_t **httpdp) {
        isc_httpd_t *httpd = *httpdp;
        isc_httpdmgr_t *httpdmgr = httpd->mgr;
 
@@ -321,8 +301,7 @@ isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
 }
 
 static void
-httpdmgr_destroy(isc_httpdmgr_t *httpdmgr)
-{
+httpdmgr_destroy(isc_httpdmgr_t *httpdmgr) {
        isc_mem_t *mctx;
        isc_httpdurl_t *url;
 
@@ -379,8 +358,7 @@ httpdmgr_destroy(isc_httpdmgr_t *httpdmgr)
 #define BUFLENOK(s) (httpd->recvbuf - (s) < HTTP_RECVLEN)
 
 static isc_result_t
-process_request(isc_httpd_t *httpd, int length)
-{
+process_request(isc_httpd_t *httpd, int length) {
        char *s;
        char *p;
        int delim;
@@ -390,6 +368,7 @@ process_request(isc_httpd_t *httpd, int length)
        httpd->recvlen += length;
 
        httpd->recvbuf[httpd->recvlen] = 0;
+       httpd->headers = NULL;
 
        /*
         * If we don't find a blank line in our buffer, return that we need
@@ -494,6 +473,8 @@ process_request(isc_httpd_t *httpd, int length)
        p = s + 1;
        s = p;
 
+       httpd->headers = s;
+
        if (strstr(s, "Connection: close") != NULL)
                httpd->flags |= HTTPD_CLOSE;
 
@@ -513,8 +494,7 @@ process_request(isc_httpd_t *httpd, int length)
 }
 
 static void
-isc_httpd_accept(isc_task_t *task, isc_event_t *ev)
-{
+isc_httpd_accept(isc_task_t *task, isc_event_t *ev) {
        isc_result_t result;
        isc_httpdmgr_t *httpdmgr = ev->ev_arg;
        isc_httpd_t *httpd;
@@ -609,8 +589,8 @@ isc_httpd_accept(isc_task_t *task, isc_event_t *ev)
 }
 
 static isc_result_t
-render_404(const char *url, const char *querystring,
-          void *arg,
+render_404(const char *url, isc_httpdurl_t *urlinfo,
+          const char *querystring, const char *headers, void *arg,
           unsigned int *retcode, const char **retmsg,
           const char **mimetype, isc_buffer_t *b,
           isc_httpdfree_t **freecb, void **freecb_args)
@@ -618,7 +598,9 @@ render_404(const char *url, const char *querystring,
        static char msg[] = "No such URL.";
 
        UNUSED(url);
+       UNUSED(urlinfo);
        UNUSED(querystring);
+       UNUSED(headers);
        UNUSED(arg);
 
        *retcode = 404;
@@ -633,8 +615,8 @@ render_404(const char *url, const char *querystring,
 }
 
 static isc_result_t
-render_500(const char *url, const char *querystring,
-          void *arg,
+render_500(const char *url, isc_httpdurl_t *urlinfo,
+          const char *querystring, const char *headers, void *arg,
           unsigned int *retcode, const char **retmsg,
           const char **mimetype, isc_buffer_t *b,
           isc_httpdfree_t **freecb, void **freecb_args)
@@ -642,7 +624,9 @@ render_500(const char *url, const char *querystring,
        static char msg[] = "Internal server failure.";
 
        UNUSED(url);
+       UNUSED(urlinfo);
        UNUSED(querystring);
+       UNUSED(headers);
        UNUSED(arg);
 
        *retcode = 500;
@@ -657,8 +641,7 @@ render_500(const char *url, const char *querystring,
 }
 
 static void
-isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev)
-{
+isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) {
        isc_region_t r;
        isc_result_t result;
        isc_httpd_t *httpd = ev->ev_arg;
@@ -710,8 +693,9 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev)
                url = ISC_LIST_NEXT(url, link);
        }
        if (url == NULL)
-               result = httpd->mgr->render_404(httpd->url, httpd->querystring,
-                                               NULL,
+               result = httpd->mgr->render_404(httpd->url, NULL,
+                                               httpd->querystring,
+                                               NULL, NULL,
                                                &httpd->retcode,
                                                &httpd->retmsg,
                                                &httpd->mimetype,
@@ -719,14 +703,18 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev)
                                                &httpd->freecb,
                                                &httpd->freecb_arg);
        else
-               result = url->action(httpd->url, httpd->querystring,
+               result = url->action(httpd->url, url,
+                                    httpd->querystring,
+                                    httpd->headers,
                                     url->action_arg,
                                     &httpd->retcode, &httpd->retmsg,
                                     &httpd->mimetype, &httpd->bodybuffer,
                                     &httpd->freecb, &httpd->freecb_arg);
        if (result != ISC_R_SUCCESS) {
-               result = httpd->mgr->render_500(httpd->url, httpd->querystring,
-                                               NULL, &httpd->retcode,
+               result = httpd->mgr->render_500(httpd->url, url,
+                                               httpd->querystring,
+                                               NULL, NULL,
+                                               &httpd->retcode,
                                                &httpd->retmsg,
                                                &httpd->mimetype,
                                                &httpd->bodybuffer,
@@ -739,9 +727,19 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev)
        isc_httpd_addheader(httpd, "Content-Type", httpd->mimetype);
        isc_httpd_addheader(httpd, "Date", datebuf);
        isc_httpd_addheader(httpd, "Expires", datebuf);
-       isc_httpd_addheader(httpd, "Last-Modified", datebuf);
-       isc_httpd_addheader(httpd, "Pragma: no-cache", NULL);
-       isc_httpd_addheader(httpd, "Cache-Control: no-cache", NULL);
+
+       if (url != NULL && url->isstatic) {
+               char loadbuf[32];
+               isc_time_formathttptimestamp(&url->loadtime,
+                                            loadbuf, sizeof(loadbuf));
+               isc_httpd_addheader(httpd, "Last-Modified", loadbuf);
+               isc_httpd_addheader(httpd, "Cache-Control: public", NULL);
+       } else {
+               isc_httpd_addheader(httpd, "Last-Modified", datebuf);
+               isc_httpd_addheader(httpd, "Pragma: no-cache", NULL);
+               isc_httpd_addheader(httpd, "Cache-Control: no-cache", NULL);
+       }
+
        isc_httpd_addheader(httpd, "Server: libisc", NULL);
        isc_httpd_addheaderuint(httpd, "Content-Length",
                                isc_buffer_usedlength(&httpd->bodybuffer));
@@ -766,8 +764,7 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev)
 }
 
 void
-isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp)
-{
+isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp) {
        isc_httpdmgr_t *httpdmgr;
        isc_httpd_t *httpd;
        httpdmgr = *httpdmgrp;
@@ -794,8 +791,7 @@ isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp)
 }
 
 static isc_result_t
-grow_headerspace(isc_httpd_t *httpd)
-{
+grow_headerspace(isc_httpd_t *httpd) {
        char *newspace;
        unsigned int newlen;
        isc_region_t r;
@@ -816,8 +812,7 @@ grow_headerspace(isc_httpd_t *httpd)
 }
 
 isc_result_t
-isc_httpd_response(isc_httpd_t *httpd)
-{
+isc_httpd_response(isc_httpd_t *httpd) {
        isc_result_t result;
        unsigned int needlen;
 
@@ -869,8 +864,7 @@ isc_httpd_addheader(isc_httpd_t *httpd, const char *name,
 }
 
 isc_result_t
-isc_httpd_endheaders(isc_httpd_t *httpd)
-{
+isc_httpd_endheaders(isc_httpd_t *httpd) {
        isc_result_t result;
 
        while (isc_buffer_availablelength(&httpd->headerbuffer) < 2) {
@@ -912,8 +906,7 @@ isc_httpd_addheaderuint(isc_httpd_t *httpd, const char *name, int val) {
 }
 
 static void
-isc_httpd_senddone(isc_task_t *task, isc_event_t *ev)
-{
+isc_httpd_senddone(isc_task_t *task, isc_event_t *ev) {
        isc_httpd_t *httpd = ev->ev_arg;
        isc_region_t r;
        isc_socketevent_t *sev = (isc_socketevent_t *)ev;
@@ -977,8 +970,7 @@ out:
 }
 
 static void
-reset_client(isc_httpd_t *httpd)
-{
+reset_client(isc_httpd_t *httpd) {
        /*
         * Catch errors here.  We MUST be in RECV mode, and we MUST NOT have
         * any outstanding buffers.  If we have buffers, we have a leak.
@@ -989,6 +981,7 @@ reset_client(isc_httpd_t *httpd)
 
        httpd->recvbuf[0] = 0;
        httpd->recvlen = 0;
+       httpd->headers = NULL;
        httpd->method = ISC_HTTPD_METHODUNKNOWN;
        httpd->url = NULL;
        httpd->querystring = NULL;
@@ -1002,6 +995,14 @@ reset_client(isc_httpd_t *httpd)
 isc_result_t
 isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url,
                    isc_httpdaction_t *func, void *arg)
+{
+       return (isc_httpdmgr_addurl2(httpdmgr, url, ISC_FALSE, func, arg));
+}
+
+isc_result_t
+isc_httpdmgr_addurl2(isc_httpdmgr_t *httpdmgr, const char *url,
+                    isc_boolean_t isstatic,
+                    isc_httpdaction_t *func, void *arg)
 {
        isc_httpdurl_t *item;
 
@@ -1022,6 +1023,9 @@ isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url,
 
        item->action = func;
        item->action_arg = arg;
+       item->isstatic = isstatic;
+       isc_time_now(&item->loadtime);
+
        ISC_LINK_INIT(item, link);
        ISC_LIST_APPEND(httpdmgr->urls, item, link);
 
index ba7f900198e464e8cca15512796f4a245191d5bb..d3b58dde2e25be4f084732a92ced117543f5b45f 100644 (file)
 #include <isc/types.h>
 #include <isc/mutex.h>
 #include <isc/task.h>
+#include <isc/time.h>
+
+/*%
+ * HTTP urls.  These are the URLs we manage, and the function to call to
+ * provide the data for it.  We pass in the base url (so the same function
+ * can handle multiple requests), and a structure to fill in to return a
+ * result to the client.  We also pass in a pointer to be filled in for
+ * the data cleanup function.
+ */
+struct isc_httpdurl {
+       char                           *url;
+       isc_httpdaction_t              *action;
+       void                           *action_arg;
+       isc_boolean_t                   isstatic;
+       isc_time_t                      loadtime;
+       ISC_LINK(isc_httpdurl_t)        link;
+};
 
 #define HTTPD_EVENTCLASS               ISC_EVENTCLASS(4300)
 #define HTTPD_SHUTDOWN                 (HTTPD_EVENTCLASS + 0x0001)
@@ -49,6 +66,11 @@ isc_result_t
 isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url,
                    isc_httpdaction_t *func, void *arg);
 
+isc_result_t
+isc_httpdmgr_addurl2(isc_httpdmgr_t *httpdmgr, const char *url,
+                    isc_boolean_t isstatic,
+                    isc_httpdaction_t *func, void *arg);
+
 isc_result_t
 isc_httpd_response(isc_httpd_t *httpd);
 
index 19b9a33335fadece43b0f8e282e81a854ab53db2..da80601c3f9abc3130394547a21f6229ba4802a4 100644 (file)
@@ -103,7 +103,9 @@ typedef int (*isc_sockfdwatch_t)(isc_task_t *, isc_socket_t *, void *, int);
 
 /* The following cannot be listed alphabetically due to forward reference */
 typedef isc_result_t (isc_httpdaction_t)(const char *url,
+                                        isc_httpdurl_t *urlinfo,
                                         const char *querystring,
+                                        const char *headers,
                                         void *arg,
                                         unsigned int *retcode,
                                         const char **retmsg,
index d81d854a24e291a13a4c8aa6e4ba0fa77b49bb40..179ab52866460b399d39c784ea30f19d7a64f259 100644 (file)
@@ -315,6 +315,16 @@ isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len);
  *
  */
 
+isc_result_t
+isc_time_parsehttptimestamp(char *input, isc_time_t *t);
+/*%<
+ * Parse the time in 'input' into the isc_time_t pointed to by 't',
+ * expecting a format like "Mon, 30 Aug 2000 04:06:47 GMT"
+ *
+ *  Requires:
+ *\li      'buf' and 't' are not NULL.
+ */
+
 void
 isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len);
 /*%<
index e820afb1eaa079df2014475d2164e7dc0d366924..941a3188bbbbc54401e2f176b447a0774837e557 100644 (file)
@@ -407,6 +407,24 @@ isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) {
        INSIST(flen < len);
 }
 
+isc_result_t
+isc_time_parsehttptimestamp(char *buf, isc_time_t *t) {
+       struct tm t_tm;
+       time_t when;
+       char *p;
+
+       REQUIRE(buf != NULL);
+       REQUIRE(t != NULL);
+       p = strptime(buf, "%a, %d %b %Y %H:%M:%S %Z", &t_tm);
+       if (p == NULL)
+               return (ISC_R_UNEXPECTED);
+       when = timegm(&t_tm);
+       if (when == -1)
+               return (ISC_R_UNEXPECTED);
+       isc_time_set(t, when, 0);
+       return (ISC_R_SUCCESS);
+}
+
 void
 isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) {
        time_t now;