]> granicus.if.org Git - apache/commitdiff
Enhance the util_ldap cache-info page to display the current contents of the search...
authorBradley Nicholes <bnicholes@apache.org>
Wed, 16 Jun 2004 23:25:27 +0000 (23:25 +0000)
committerBradley Nicholes <bnicholes@apache.org>
Wed, 16 Jun 2004 23:25:27 +0000 (23:25 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@103974 13f79535-47bb-0310-9956-ffa450edef68

include/util_ldap.h
modules/experimental/util_ldap.c
modules/experimental/util_ldap_cache.c
modules/experimental/util_ldap_cache.h
modules/experimental/util_ldap_cache_mgr.c

index 1f3089fca14f94282c951535f6f4c4a26257af34..6f4bce5d1a387f49364695213c4a0457113ad16d 100644 (file)
@@ -279,16 +279,6 @@ LDAP_DECLARE(int) util_ldap_ssl_supported(request_rec *r);
  */
 apr_status_t util_ldap_cache_init(apr_pool_t *pool, util_ldap_state_t *st);
 
-/**
- * Display formatted stats for cache
- * @param The pool to allocate the returned string from
- * @tip This function returns a string allocated from the provided pool that describes
- *      various stats about the cache.
- * @deffunc char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st)
- */
-char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st);
-
-
 /* from apr_ldap_cache_mgr.c */
 
 /**
@@ -298,7 +288,7 @@ char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st);
  *      various stats about the cache.
  * @deffunc char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st)
  */
-char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st);
+char *util_ald_cache_display(request_rec *r, util_ldap_state_t *st);
 
 #endif /* APR_HAS_LDAP */
 #endif /* UTIL_LDAP_H */
index 6493527880843822527df6377f4ffdbd018e65d8..761503d79fcd8554983ca1fc124a9ff07739553e 100644 (file)
@@ -134,22 +134,7 @@ int util_ldap_handler(request_rec *r)
              "<html><head><title>LDAP Cache Information</title></head>\n", r);
     ap_rputs("<body bgcolor='#ffffff'><h1 align=center>LDAP Cache Information</h1>\n", r);
 
-    ap_rputs("<p>\n"
-             "<table border='0'>\n"
-             "<tr bgcolor='#000000'>\n"
-             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name</b></font></td>"
-             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Entries</b></font></td>"
-             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg. Chain Len.</b></font></td>"
-             "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Hits</b></font></td>"
-             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Ins/Rem</b></font></td>"
-             "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Purges</b></font></td>"
-             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg Purge Time</b></font></td>"
-             "</tr>\n", r
-            );
-
-    ap_rputs(util_ald_cache_display(r->pool, st), r);
-
-    ap_rputs("</table>\n</p>\n", r);
+    util_ald_cache_display(r, st);
 
     return OK;
 }
index a8c8127479b7074af6322ac6ca4081542ecc0b5d..0225d4ce8b9c7caa9dc8bc921b25d48ef0d0b551 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 #include <apr_ldap.h>
+#include <apr_strings.h>
 #include "util_ldap.h"
 #include "util_ldap_cache.h"
 
@@ -78,6 +79,12 @@ void util_ldap_url_node_free(util_ald_cache_t *cache, void *n)
     util_ald_free(cache, node);
 }
 
+void util_ldap_url_node_display(request_rec *r, util_ald_cache_t *cache, void *n)
+{
+    util_url_node_t *node = (util_url_node_t *)n;
+
+}
+
 /* ------------------------------------------------------------------ */
 
 /* Cache functions for search nodes */
@@ -156,6 +163,27 @@ void util_ldap_search_node_free(util_ald_cache_t *cache, void *n)
     util_ald_free(cache, node);
 }
 
+void util_ldap_search_node_display(request_rec *r, util_ald_cache_t *cache, void *n)
+{
+    util_search_node_t *node = (util_search_node_t *)n;
+    char date_str[APR_CTIME_LEN+1];
+    char *buf;
+
+    apr_ctime(date_str, node->lastbind);
+
+    buf = apr_psprintf(r->pool, 
+             "<tr valign='top'>"
+             "<td nowrap>%s</td>"
+             "<td nowrap>%s</td>"
+             "<td nowrap>%s</td>"
+             "<tr>",
+         node->username,
+         node->dn,
+         date_str);
+
+    ap_rputs(buf, r);
+}
+
 /* ------------------------------------------------------------------ */
 
 unsigned long util_ldap_compare_node_hash(void *n)
@@ -203,6 +231,41 @@ void util_ldap_compare_node_free(util_ald_cache_t *cache, void *n)
     util_ald_free(cache, node);
 }
 
+void util_ldap_compare_node_display(request_rec *r, util_ald_cache_t *cache, void *n)
+{
+    util_compare_node_t *node = (util_compare_node_t *)n;
+    char date_str[APR_CTIME_LEN+1];
+    char *buf, *cmp_result;
+
+    apr_ctime(date_str, node->lastcompare);
+
+    if (node->result == LDAP_COMPARE_TRUE) {
+        cmp_result = "LDAP_COMPARE_TRUE";
+    }
+    else if (node->result == LDAP_COMPARE_FALSE) {
+        cmp_result = "LDAP_COMPARE_FALSE";
+    }
+    else {
+        cmp_result = apr_itoa(r->pool, node->result);
+    }
+
+    buf = apr_psprintf(r->pool, 
+             "<tr valign='top'>"
+             "<td nowrap>%s</td>"
+             "<td nowrap>%s</td>"
+             "<td nowrap>%s</td>"
+             "<td nowrap>%s</td>"
+             "<td nowrap>%s</td>"
+             "<tr>",
+         node->dn,
+         node->attrib,
+         node->value,
+         date_str,
+         cmp_result);
+
+    ap_rputs(buf, r);
+}
+
 /* ------------------------------------------------------------------ */
 
 unsigned long util_ldap_dn_compare_node_hash(void *n)
@@ -241,6 +304,22 @@ void util_ldap_dn_compare_node_free(util_ald_cache_t *cache, void *n)
     util_ald_free(cache, node);
 }
 
+void util_ldap_dn_compare_node_display(request_rec *r, util_ald_cache_t *cache, void *n)
+{
+    util_dn_compare_node_t *node = (util_dn_compare_node_t *)n;
+    char *buf;
+
+    buf = apr_psprintf(r->pool, 
+             "<tr valign='top'>"
+             "<td nowrap>%s</td>"
+             "<td nowrap>%s</td>"
+             "<tr>",
+         node->reqdn,
+         node->dn);
+
+    ap_rputs(buf, r);
+}
+
 
 /* ------------------------------------------------------------------ */
 apr_status_t util_ldap_cache_child_kill(void *data);
@@ -290,7 +369,8 @@ apr_status_t util_ldap_cache_init(apr_pool_t *pool, util_ldap_state_t *st)
                               util_ldap_url_node_hash,
                               util_ldap_url_node_compare,
                               util_ldap_url_node_copy,
-                              util_ldap_url_node_free);
+                              util_ldap_url_node_free,
+                              util_ldap_url_node_display);
     return APR_SUCCESS;
 }
 
index 06f179eb4a3d6350f613b0376183f0888c7575db..017ed0897279ac869938475eb16f51f9fc741836 100644 (file)
@@ -51,6 +51,7 @@ struct util_ald_cache {
     int (*compare)(void *, void *);     /* Func to compare two payloads */
     void * (*copy)(util_ald_cache_t *cache, void *); /* Func to alloc mem and copy payload to new mem */
     void (*free)(util_ald_cache_t *cache, void *); /* Func to free mem used by the payload */
+    void (*display)(request_rec *r, util_ald_cache_t *cache, void *); /* Func to display the payload contents */
     util_cache_node_t **nodes;
 
     unsigned long numpurges;    /* No. of times the cache has been purged */
@@ -157,18 +158,25 @@ unsigned long util_ldap_url_node_hash(void *n);
 int util_ldap_url_node_compare(void *a, void *b);
 void *util_ldap_url_node_copy(util_ald_cache_t *cache, void *c);
 void util_ldap_url_node_free(util_ald_cache_t *cache, void *n);
+void util_ldap_url_node_display(request_rec *r, util_ald_cache_t *cache, void *n);
+
 unsigned long util_ldap_search_node_hash(void *n);
 int util_ldap_search_node_compare(void *a, void *b);
 void *util_ldap_search_node_copy(util_ald_cache_t *cache, void *c);
 void util_ldap_search_node_free(util_ald_cache_t *cache, void *n);
+void util_ldap_search_node_display(request_rec *r, util_ald_cache_t *cache, void *n);
+
 unsigned long util_ldap_compare_node_hash(void *n);
 int util_ldap_compare_node_compare(void *a, void *b);
 void *util_ldap_compare_node_copy(util_ald_cache_t *cache, void *c);
 void util_ldap_compare_node_free(util_ald_cache_t *cache, void *n);
+void util_ldap_compare_node_display(request_rec *r, util_ald_cache_t *cache, void *n);
+
 unsigned long util_ldap_dn_compare_node_hash(void *n);
 int util_ldap_dn_compare_node_compare(void *a, void *b);
 void *util_ldap_dn_compare_node_copy(util_ald_cache_t *cache, void *c);
 void util_ldap_dn_compare_node_free(util_ald_cache_t *cache, void *n);
+void util_ldap_dn_compare_node_display(request_rec *r, util_ald_cache_t *cache, void *n);
 
 
 /* util_ldap_cache_mgr.c */
@@ -186,14 +194,14 @@ util_ald_cache_t *util_ald_create_cache(util_ldap_state_t *st,
                                 unsigned long (*hashfunc)(void *), 
                                 int (*comparefunc)(void *, void *),
                                 void * (*copyfunc)(util_ald_cache_t *cache, void *),
-                                void (*freefunc)(util_ald_cache_t *cache, void *));
+                                void (*freefunc)(util_ald_cache_t *cache, void *),
+                                void (*displayfunc)(request_rec *r, util_ald_cache_t *cache, void *));
                                 
 void util_ald_destroy_cache(util_ald_cache_t *cache);
 void *util_ald_cache_fetch(util_ald_cache_t *cache, void *payload);
 void util_ald_cache_insert(util_ald_cache_t *cache, void *payload);
 void util_ald_cache_remove(util_ald_cache_t *cache, void *payload);
-char *util_ald_cache_display_stats(apr_pool_t *p, util_ald_cache_t *cache,
-                                 char *name);
+char *util_ald_cache_display_stats(request_rec *r, util_ald_cache_t *cache, char *name, char *id);
 
 #endif /* APR_HAS_LDAP */
 #endif /* APU_LDAP_CACHE_H */
index 392ba6584c16052d1fdf61a131f5c0ac8b6bd6c4..d7bf34c409cac9b6a666680185880b8b3877e2e8 100644 (file)
@@ -222,21 +222,25 @@ util_url_node_t *util_ald_create_caches(util_ldap_state_t *st, const char *url)
                                          util_ldap_search_node_hash,
                                          util_ldap_search_node_compare,
                                          util_ldap_search_node_copy,
-                                         util_ldap_search_node_free);
+                                         util_ldap_search_node_free,
+                      util_ldap_search_node_display);
     compare_cache = util_ald_create_cache(st,
                                           util_ldap_compare_node_hash,
                                           util_ldap_compare_node_compare,
                                           util_ldap_compare_node_copy,
-                                          util_ldap_compare_node_free);
+                                          util_ldap_compare_node_free,
+                       util_ldap_compare_node_display);
     dn_compare_cache = util_ald_create_cache(st,
                                              util_ldap_dn_compare_node_hash,
                                              util_ldap_dn_compare_node_compare,
                                              util_ldap_dn_compare_node_copy,
-                                             util_ldap_dn_compare_node_free);
+                                             util_ldap_dn_compare_node_free,
+                          util_ldap_dn_compare_node_display);
 
     /* check that all the caches initialised successfully */
     if (search_cache && compare_cache && dn_compare_cache) {
 
+/*XXX This can be allocated on the stack since it will be copied anyway */
         curl = (util_url_node_t *)apr_pcalloc(st->pool, sizeof(util_url_node_t));
         curl->url = url;
         curl->search_cache = search_cache;
@@ -255,7 +259,8 @@ util_ald_cache_t *util_ald_create_cache(util_ldap_state_t *st,
                                 unsigned long (*hashfunc)(void *), 
                                 int (*comparefunc)(void *, void *),
                                 void * (*copyfunc)(util_ald_cache_t *cache, void *),
-                                void (*freefunc)(util_ald_cache_t *cache, void *))
+                                void (*freefunc)(util_ald_cache_t *cache, void *),
+                                void (*displayfunc)(request_rec *r, util_ald_cache_t *cache, void *))
 {
     util_ald_cache_t *cache;
     unsigned long i;
@@ -297,6 +302,7 @@ util_ald_cache_t *util_ald_create_cache(util_ldap_state_t *st,
     cache->compare = comparefunc;
     cache->copy = copyfunc;
     cache->free = freefunc;
+    cache->display = displayfunc;
 
     cache->fullmark = cache->maxentries / 4 * 3;
     cache->marktime = 0;
@@ -437,14 +443,15 @@ void util_ald_cache_remove(util_ald_cache_t *cache, void *payload)
     cache->numentries--;
 }
 
-char *util_ald_cache_display_stats(apr_pool_t *p, util_ald_cache_t *cache, char *name)
+char *util_ald_cache_display_stats(request_rec *r, util_ald_cache_t *cache, char *name, char *id)
 {
     unsigned long i;
     int totchainlen = 0;
     int nchains = 0;
     double chainlen;
     util_cache_node_t *n;
-    char *buf;
+    char *buf, *buf2;
+    apr_pool_t *p = r->pool;
 
     if (cache == NULL) {
         return "";
@@ -454,45 +461,56 @@ char *util_ald_cache_display_stats(apr_pool_t *p, util_ald_cache_t *cache, char
         if (cache->nodes[i] != NULL) {
             nchains++;
             for (n = cache->nodes[i]; n != NULL; n = n->next)
-               totchainlen++;
+            totchainlen++;
         }
     }
     chainlen = nchains? (double)totchainlen / (double)nchains : 0;
 
+    if (id) {
+        buf2 = apr_psprintf(p, 
+                 "<a href=\"%s?%s\">%s</a>",
+             r->uri,
+             id,
+             name);
+    }
+    else {
+        buf2 = name;
+    }
+
     buf = apr_psprintf(p, 
              "<tr valign='top'>"
              "<td nowrap>%s</td>"
              "<td align='right' nowrap>%lu (%.0f%% full)</td>"
              "<td align='right'>%.1f</td>"
-            "<td align='right'>%lu/%lu</td>"
-            "<td align='right'>%.0f%%</td>"
+             "<td align='right'>%lu/%lu</td>"
+             "<td align='right'>%.0f%%</td>"
              "<td align='right'>%lu/%lu</td>",
-             name,
-            cache->numentries, 
-            (double)cache->numentries / (double)cache->maxentries * 100.0,
-             chainlen,
-            cache->hits,            
-            cache->fetches,
-            (cache->fetches > 0 ? (double)(cache->hits) / (double)(cache->fetches) * 100.0 : 100.0),
-            cache->inserts,
-            cache->removes);
+         buf2,
+         cache->numentries, 
+         (double)cache->numentries / (double)cache->maxentries * 100.0,
+         chainlen,
+         cache->hits,
+         cache->fetches,
+         (cache->fetches > 0 ? (double)(cache->hits) / (double)(cache->fetches) * 100.0 : 100.0),
+         cache->inserts,
+         cache->removes);
 
     if (cache->numpurges) {
         char str_ctime[APR_CTIME_LEN];
 
         apr_ctime(str_ctime, cache->last_purge);
         buf = apr_psprintf(p,
-                           "%s"
-                          "<td align='right'>%lu</td>\n"
-                           "<td align='right' nowrap>%s</td>\n", 
-                           buf,
-                          cache->numpurges,
-                          str_ctime);
+                 "%s"
+                 "<td align='right'>%lu</td>\n"
+                 "<td align='right' nowrap>%s</td>\n", 
+             buf,
+             cache->numpurges,
+             str_ctime);
     }
     else {
         buf = apr_psprintf(p, 
-                           "%s<td colspan='2' align='center'>(none)</td>\n",
-                           buf);
+                 "%s<td colspan='2' align='center'>(none)</td>\n",
+             buf);
     }
 
     buf = apr_psprintf(p, "%s<td align='right'>%.2g</td>\n</tr>", buf, cache->avg_purgetime);
@@ -500,10 +518,16 @@ char *util_ald_cache_display_stats(apr_pool_t *p, util_ald_cache_t *cache, char
     return buf;
 }
 
-char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st)
+char *util_ald_cache_display(request_rec *r, util_ldap_state_t *st)
 {
-    unsigned long i;
+    unsigned long i,j;
     char *buf, *t1, *t2, *t3;
+    char *id1, *id2, *id3;
+    char *argfmt = "cache=%s&id=%d&off=%d";
+    char *scanfmt = "cache=%4s&id=%u&off=%u%1s";
+    apr_pool_t *pool = r->pool;
+    util_cache_node_t *p;
+    util_url_node_t *n;
 
     util_ald_cache_t *util_ldap_cache = st->util_ldap_cache;
 
@@ -512,30 +536,131 @@ char *util_ald_cache_display(apr_pool_t *pool, util_ldap_state_t *st)
         return "<tr valign='top'><td nowrap colspan=7>Cache has not been enabled/initialised.</td></tr>";
     }
 
-    buf = util_ald_cache_display_stats(pool, st->util_ldap_cache, "LDAP URL Cache");
+    if (r->args && strlen(r->args)) {
+        char cachetype[5], lint[2];
+        unsigned int id, off;
+        int ret;
 
-    for (i=0; i < util_ldap_cache->size; ++i) {
-        util_cache_node_t *p;
-        for (p = util_ldap_cache->nodes[i]; p != NULL; p = p->next) {
-            util_url_node_t *n;
+        if ((3 == sscanf(r->args, scanfmt, cachetype, &id, &off, lint)) &&
+            (id < util_ldap_cache->size)) {
 
+            p = util_ldap_cache->nodes[id];
             n = (util_url_node_t *)p->payload;
 
-            t1 = apr_psprintf(pool, "%s (Searches)", n->url);
-            t2 = apr_psprintf(pool, "%s (Compares)", n->url);
-            t3 = apr_psprintf(pool, "%s (DNCompares)", n->url);
-
-            buf = apr_psprintf(pool, "%s\n\n"
-                                     "%s\n\n"
-                                     "%s\n\n"
-                                     "%s\n\n",
-                                     buf,
-                                     util_ald_cache_display_stats(pool, n->search_cache, t1),
-                                     util_ald_cache_display_stats(pool, n->compare_cache, t2),
-                                     util_ald_cache_display_stats(pool, n->dn_compare_cache, t3)
-                              );
+            ap_rputs(apr_psprintf(r->pool, 
+                     "<p>\n"
+                     "<table border='0'>\n"
+                     "<tr>\n"
+                     "<td bgcolor='#000000'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name:</b></font></td>"
+                     "<td bgcolor='#ffffff'><font size='-1' face='Arial,Helvetica' color='#000000'><b>%s (%s)</b></font></td>"
+                     "</tr>\n"
+                     "</table>\n</p>\n",
+                 n->url,
+                 cachetype[0] == 's' ? "Search" : (cachetype[0] == 'c' ? "Compares" : "DNCompares")), r);
+            
+            switch (cachetype[0]) {
+                case 's':
+                    ap_rputs("<p>\n"
+                             "<table border='0'>\n"
+                             "<tr bgcolor='#000000'>\n"
+                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>LDAP Filter</b></font></td>"
+                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>User Name</b></font></td>"
+                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Last Bind</b></font></td>"
+                             "</tr>\n", r
+                            );
+                    for (i=0; i < n->search_cache->size; ++i) {
+                        for (p = n->search_cache->nodes[i]; p != NULL; p = p->next) {
+
+                            (*n->search_cache->display)(r, n->search_cache, p->payload);
+                        }
+                    }
+                    ap_rputs("</table>\n</p>\n", r);
+                    break;
+                case 'c':
+                    ap_rputs("<p>\n"
+                             "<table border='0'>\n"
+                             "<tr bgcolor='#000000'>\n"
+                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>DN</b></font></td>"
+                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Attribute</b></font></td>"
+                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Value</b></font></td>"
+                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Last Compare</b></font></td>"
+                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Result</b></font></td>"
+                             "</tr>\n", r
+                            );
+                    for (i=0; i < n->compare_cache->size; ++i) {
+                        for (p = n->compare_cache->nodes[i]; p != NULL; p = p->next) {
+
+                            (*n->compare_cache->display)(r, n->compare_cache, p->payload);
+                        }
+                    }
+                    ap_rputs("</table>\n</p>\n", r);
+                    break;
+                case 'd':
+                    ap_rputs("<p>\n"
+                             "<table border='0'>\n"
+                             "<tr bgcolor='#000000'>\n"
+                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Require DN</b></font></td>"
+                             "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Actual DN</b></font></td>"
+                             "</tr>\n", r
+                            );
+                    for (i=0; i < n->dn_compare_cache->size; ++i) {
+                        for (p = n->dn_compare_cache->nodes[i]; p != NULL; p = p->next) {
+
+                            (*n->dn_compare_cache->display)(r, n->dn_compare_cache, p->payload);
+                        }
+                    }
+                    ap_rputs("</table>\n</p>\n", r);
+                    break;
+                default:
+                    break;
+            }
+
+        }
+    }
+    else {
+        ap_rputs("<p>\n"
+                 "<table border='0'>\n"
+                 "<tr bgcolor='#000000'>\n"
+                 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Cache Name</b></font></td>"
+                 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Entries</b></font></td>"
+                 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg. Chain Len.</b></font></td>"
+                 "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Hits</b></font></td>"
+                 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Ins/Rem</b></font></td>"
+                 "<td colspan='2'><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Purges</b></font></td>"
+                 "<td><font size='-1' face='Arial,Helvetica' color='#ffffff'><b>Avg Purge Time</b></font></td>"
+                 "</tr>\n", r
+                );
+
+
+        buf = util_ald_cache_display_stats(r, st->util_ldap_cache, "LDAP URL Cache", NULL);
+    
+        for (i=0; i < util_ldap_cache->size; ++i) {
+            for (p = util_ldap_cache->nodes[i],j=0; p != NULL; p = p->next,j++) {
+    
+                n = (util_url_node_t *)p->payload;
+    
+                t1 = apr_psprintf(pool, "%s (Searches)", n->url);
+                t2 = apr_psprintf(pool, "%s (Compares)", n->url);
+                t3 = apr_psprintf(pool, "%s (DNCompares)", n->url);
+                id1 = apr_psprintf(pool, argfmt, "srch", i, j);
+                id2 = apr_psprintf(pool, argfmt, "cmpr", i, j);
+                id3 = apr_psprintf(pool, argfmt, "dncp", i, j);
+    
+                buf = apr_psprintf(pool, "%s\n\n"
+                                         "%s\n\n"
+                                         "%s\n\n"
+                                         "%s\n\n",
+                                         buf,
+                                         util_ald_cache_display_stats(r, n->search_cache, t1, id1),
+                                         util_ald_cache_display_stats(r, n->compare_cache, t2, id2),
+                                         util_ald_cache_display_stats(r, n->dn_compare_cache, t3, id3)
+                                  );
+            }
         }
+        ap_rputs(buf, r);
+        ap_rputs("</table>\n</p>\n", r);
     }
+
     return buf;
 }