]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
* Implement full auto status ("key: value" type status output).
authorStefan Eissing <icing@apache.org>
Tue, 19 Apr 2022 14:11:39 +0000 (14:11 +0000)
committerStefan Eissing <icing@apache.org>
Tue, 19 Apr 2022 14:11:39 +0000 (14:11 +0000)
   Especially not only status summary counts for certificates and
   OCSP stapling but also lists. Auto status format is similar to
   what was used for mod_proxy_balancer.
   [Rainer Jung]

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1900039 13f79535-47bb-0310-9956-ffa450edef68

changes-entries/md_auto_status.txt [new file with mode: 0644]
modules/md/md_version.h
modules/md/mod_md_status.c
test/modules/md/test_920_status.py

diff --git a/changes-entries/md_auto_status.txt b/changes-entries/md_auto_status.txt
new file mode 100644 (file)
index 0000000..34faddd
--- /dev/null
@@ -0,0 +1,5 @@
+ * Implement full auto status ("key: value" type status output).
+   Especially not only status summary counts for certificates and
+   OCSP stapling but also lists. Auto status format is similar to
+   what was used for mod_proxy_balancer.
+   [Rainer Jung]
index ae723f621ff2342518f7447135f63da16e52d55e..699d55107e509b44def1b2917b3a049202329159 100644 (file)
@@ -27,7 +27,7 @@
  * @macro
  * Version number of the md module as c string
  */
-#define MOD_MD_VERSION "2.4.10"
+#define MOD_MD_VERSION "2.4.12"
 
 /**
  * @macro
@@ -35,7 +35,7 @@
  * release. This is a 24 bit number with 8 bits for major number, 8 bits
  * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
  */
-#define MOD_MD_VERSION_NUM 0x02040a
+#define MOD_MD_VERSION_NUM 0x02040c
 
 #define MD_ACME_DEF_URL    "https://acme-v02.api.letsencrypt.org/directory"
 
index 390290b85cd48ca3872adca02a4386e2e7410ae8..59f4e0ffd76971b3922bbcc425dc62ed0981baf8 100644 (file)
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #include <assert.h>
 #include <apr_optional.h>
 #include <apr_time.h>
@@ -55,6 +55,7 @@
 
 #define APACHE_PREFIX               "/.httpd/"
 #define MD_STATUS_RESOURCE          APACHE_PREFIX"certificate-status"
+#define HTML_STATUS(X)              (!((X)->flags & AP_STATUS_SHORT))
 
 int md_http_cert_status(request_rec *r)
 {
@@ -66,13 +67,13 @@ int md_http_cert_status(request_rec *r)
     const char *keyname;
     apr_bucket_brigade *bb;
     apr_status_t rv;
-    
+
     if (!r->parsed_uri.path || strcmp(MD_STATUS_RESOURCE, r->parsed_uri.path))
         return DECLINED;
-        
+
     ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
                   "requesting status for: %s", r->hostname);
-    
+
     /* We are looking for information about a staged certificate */
     sc = ap_get_module_config(r->server->module_config, &md_module);
     if (!sc || !sc->mc || !sc->mc->reg || !sc->mc->certificate_status_enabled) return DECLINED;
@@ -84,7 +85,7 @@ int md_http_cert_status(request_rec *r)
                       "md(%s): status supports only GET", md->name);
         return HTTP_NOT_IMPLEMENTED;
     }
-    
+
     ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
                   "requesting status for MD: %s", md->name);
 
@@ -94,7 +95,7 @@ int md_http_cert_status(request_rec *r)
                       "loading md status for %s", md->name);
         return HTTP_INTERNAL_SERVER_ERROR;
     }
-    
+
     ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
                   "status for MD: %s is %s", md->name, md_json_writep(mdj, r->pool, MD_JSON_FMT_INDENT));
 
@@ -124,23 +125,23 @@ int md_http_cert_status(request_rec *r)
         }
         md_json_setj(cj, resp, keyname, NULL );
     }
-    
+
     if (md_json_has_key(mdj, MD_KEY_RENEWAL, NULL)) {
            /* copy over the information we want to make public about this:
             *  - when not finished, add an empty object to indicate something is going on
             *  - when a certificate is staged, add the information from that */
            cj = md_json_getj(mdj, MD_KEY_RENEWAL, MD_KEY_CERT, NULL);
-           cj = cj? cj : md_json_create(r->pool);
+           cj = cj? cj : md_json_create(r->pool);
            md_json_setj(cj, resp, MD_KEY_RENEWAL, MD_KEY_CERT, NULL);
      }
-    
+
     ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "md[%s]: sending status", md->name);
-    apr_table_set(r->headers_out, "Content-Type", "application/json"); 
+    apr_table_set(r->headers_out, "Content-Type", "application/json");
     bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
     md_json_writeb(resp, MD_JSON_FMT_INDENT, bb);
     ap_pass_brigade(r->output_filters, bb);
     apr_brigade_cleanup(bb);
-    
+
     return DONE;
 }
 
@@ -151,10 +152,12 @@ typedef struct {
     apr_pool_t *p;
     const md_mod_conf_t *mc;
     apr_bucket_brigade *bb;
+    int flags;
+    const char *prefix;
     const char *separator;
 } status_ctx;
 
-typedef struct status_info status_info; 
+typedef struct status_info status_info;
 
 static void add_json_val(status_ctx *ctx, md_json_t *j);
 
@@ -179,13 +182,19 @@ static void si_val_status(status_ctx *ctx, md_json_t *mdj, const status_info *in
         case MD_S_EXPIRED_DEPRECATED:
         case MD_S_COMPLETE:
             until = md_json_get_time(mdj, MD_KEY_CERT, MD_KEY_VALID, MD_KEY_UNTIL, NULL);
-            s = (!until || until > apr_time_now())? "good" : "expired"; 
+            s = (!until || until > apr_time_now())? "good" : "expired";
             break;
         case MD_S_ERROR: s = "error"; break;
         case MD_S_MISSING_INFORMATION: s = "missing information"; break;
         default: break;
     }
-    apr_brigade_puts(ctx->bb, NULL, NULL, s);
+    if (HTML_STATUS(ctx)) {
+        apr_brigade_puts(ctx->bb, NULL, NULL, s);
+    }
+    else {
+        apr_brigade_printf(ctx->bb, NULL, NULL, "%s%s: %s\n",
+                           ctx->prefix, info->label, s);
+    }
 }
 
 static void si_val_url(status_ctx *ctx, md_json_t *mdj, const status_info *info)
@@ -195,19 +204,28 @@ static void si_val_url(status_ctx *ctx, md_json_t *mdj, const status_info *info)
     s = url = md_json_gets(mdj, info->key, NULL);
     if (!url) return;
     s = md_get_ca_name_from_url(ctx->p, url);
-    apr_brigade_printf(ctx->bb, NULL, NULL, "<a href='%s'>%s</a>",
-                       ap_escape_html2(ctx->p, url, 1), 
-                       ap_escape_html2(ctx->p, s, 1));
+    if (HTML_STATUS(ctx)) {
+        apr_brigade_printf(ctx->bb, NULL, NULL, "<a href='%s'>%s</a>",
+                           ap_escape_html2(ctx->p, url, 1),
+                           ap_escape_html2(ctx->p, s, 1));
+    }
+    else {
+        apr_brigade_printf(ctx->bb, NULL, NULL, "%s%sName: %s\n",
+                           ctx->prefix, info->label, s);
+        apr_brigade_printf(ctx->bb, NULL, NULL, "%s%sURL: %s\n",
+                           ctx->prefix, info->label, url);
+    }
 }
 
-static void print_date(apr_bucket_brigade *bb, apr_time_t timestamp, const char *title)
+static void print_date(status_ctx *ctx, apr_time_t timestamp, const char *title)
 {
+    apr_bucket_brigade *bb = ctx->bb;
     if (timestamp > 0) {
         char ts[128];
         char ts2[128];
         apr_time_exp_t texp;
         apr_size_t len;
-        
+
         apr_time_exp_gmt(&texp, timestamp);
         apr_strftime(ts, &len, sizeof(ts2)-1, "%Y-%m-%d", &texp);
         ts[len] = '\0';
@@ -216,14 +234,21 @@ static void print_date(apr_bucket_brigade *bb, apr_time_t timestamp, const char
             ts2[len] = '\0';
             title = ts2;
         }
-        apr_brigade_printf(bb, NULL, NULL, 
-                           "<span title='%s' style='white-space: nowrap;'>%s</span>", 
-                           ap_escape_html2(bb->p, title, 1), ts);
+        if (HTML_STATUS(ctx)) {
+            apr_brigade_printf(bb, NULL, NULL,
+                               "<span title='%s' style='white-space: nowrap;'>%s</span>",
+                               ap_escape_html2(bb->p, title, 1), ts);
+        }
+        else {
+            apr_brigade_printf(bb, NULL, NULL, "%s%s: %s\n",
+                               ctx->prefix, title, ts);
+        }
     }
 }
 
-static void print_time(apr_bucket_brigade *bb, const char *label, apr_time_t t)
+static void print_time(status_ctx *ctx, const char *label, apr_time_t t)
 {
+    apr_bucket_brigade *bb = ctx->bb;
     apr_time_t now;
     const char *pre, *post, *sep;
     char ts[APR_RFC822_DATE_LEN];
@@ -231,7 +256,7 @@ static void print_time(apr_bucket_brigade *bb, const char *label, apr_time_t t)
     apr_time_exp_t texp;
     apr_size_t len;
     apr_interval_time_t delta;
-    
+
     if (t == 0) {
         /* timestamp is 0, we use that for "not set" */
         return;
@@ -241,25 +266,32 @@ static void print_time(apr_bucket_brigade *bb, const char *label, apr_time_t t)
     pre = post = "";
     sep = (label && strlen(label))? " " : "";
     delta = 0;
-    apr_rfc822_date(ts, t);
-    if (t > now) {
-        delta = t - now;
-        pre = "in ";
-    }
-    else {
-        delta = now - t;
-        post = " ago";
-    }
-    if (delta >= (4 * apr_time_from_sec(MD_SECS_PER_DAY))) {
-        apr_strftime(ts2, &len, sizeof(ts2)-1, "%Y-%m-%d", &texp);
-        ts2[len] = '\0';
-        apr_brigade_printf(bb, NULL, NULL, "%s%s<span title='%s' "
-                           "style='white-space: nowrap;'>%s</span>", 
-                           label, sep, ts, ts2); 
+    if (HTML_STATUS(ctx)) {
+        apr_rfc822_date(ts, t);
+        if (t > now) {
+            delta = t - now;
+            pre = "in ";
+        }
+        else {
+            delta = now - t;
+            post = " ago";
+        }
+        if (delta >= (4 * apr_time_from_sec(MD_SECS_PER_DAY))) {
+            apr_strftime(ts2, &len, sizeof(ts2)-1, "%Y-%m-%d", &texp);
+            ts2[len] = '\0';
+            apr_brigade_printf(bb, NULL, NULL, "%s%s<span title='%s' "
+                               "style='white-space: nowrap;'>%s</span>",
+                               label, sep, ts, ts2);
+        }
+        else {
+            apr_brigade_printf(bb, NULL, NULL, "%s%s<span title='%s'>%s%s%s</span>",
+                               label, sep, ts, pre, md_duration_roughly(bb->p, delta), post);
+        }
     }
     else {
-        apr_brigade_printf(bb, NULL, NULL, "%s%s<span title='%s'>%s%s%s</span>", 
-                           label, sep, ts, pre, md_duration_roughly(bb->p, delta), post); 
+        delta = t - now;
+        apr_brigade_printf(bb, NULL, NULL, "%s%s: %" APR_TIME_T_FMT "\n",
+                           ctx->prefix, label, apr_time_sec(delta));
     }
 }
 
@@ -267,37 +299,51 @@ static void si_val_valid_time(status_ctx *ctx, md_json_t *mdj, const status_info
 {
     const char *sfrom, *suntil, *sep, *title;
     apr_time_t from, until;
-    
+
     sep = NULL;
     sfrom = md_json_gets(mdj, info->key, MD_KEY_FROM, NULL);
     from = sfrom? apr_date_parse_rfc(sfrom) : 0;
     suntil = md_json_gets(mdj, info->key, MD_KEY_UNTIL, NULL);
     until = suntil?apr_date_parse_rfc(suntil) : 0;
-    
-    if (from > apr_time_now()) {
-        apr_brigade_puts(ctx->bb, NULL, NULL, "from ");
-        print_date(ctx->bb, from, sfrom);
-        sep = " ";
-    }
-    if (until) {
-        if (sep) apr_brigade_puts(ctx->bb, NULL, NULL, sep);
-        apr_brigade_puts(ctx->bb, NULL, NULL, "until ");
-        title = sfrom? apr_psprintf(ctx->p, "%s - %s", sfrom, suntil) : suntil;
-        print_date(ctx->bb, until, title);
+
+    if (HTML_STATUS(ctx)) {
+        if (from > apr_time_now()) {
+            apr_brigade_puts(ctx->bb, NULL, NULL, "from ");
+            print_date(ctx, from, sfrom);
+            sep = " ";
+        }
+        if (until) {
+            if (sep) apr_brigade_puts(ctx->bb, NULL, NULL, sep);
+            apr_brigade_puts(ctx->bb, NULL, NULL, "until ");
+            title = sfrom? apr_psprintf(ctx->p, "%s - %s", sfrom, suntil) : suntil;
+            print_date(ctx, until, title);
+        }
+    }
+    else {
+        if (from > apr_time_now()) {
+            print_date(ctx, from,
+            apr_pstrcat(ctx->p, info->label, "From", NULL));
+        }
+        if (until) {
+            print_date(ctx, from,
+            apr_pstrcat(ctx->p, info->label, "Until", NULL));
+        }
     }
 }
 
 static void si_add_header(status_ctx *ctx, const status_info *info)
 {
-    const char *html = ap_escape_html2(ctx->p, info->label, 1);
-    apr_brigade_printf(ctx->bb, NULL, NULL, "<th class=\"%s\">%s</th>", html, html);
+    if (HTML_STATUS(ctx)) {
+        const char *html = ap_escape_html2(ctx->p, info->label, 1);
+        apr_brigade_printf(ctx->bb, NULL, NULL, "<th class=\"%s\">%s</th>", html, html);
+    }
 }
 
 static void si_val_cert_valid_time(status_ctx *ctx, md_json_t *mdj, const status_info *info)
 {
     md_json_t *jcert;
     status_info sub = *info;
-    
+
     sub.key = MD_KEY_VALID;
     jcert = md_json_getj(mdj, info->key, NULL);
     if (jcert) si_val_valid_time(ctx, jcert, &sub);
@@ -307,7 +353,7 @@ static void si_val_ca_url(status_ctx *ctx, md_json_t *mdj, const status_info *in
 {
     md_json_t *jcert;
     status_info sub = *info;
-    
+
     sub.key = MD_KEY_URL;
     jcert = md_json_getj(mdj, info->key, NULL);
     if (jcert) si_val_url(ctx, jcert, &sub);
@@ -324,83 +370,139 @@ static int count_certs(void *baton, const char *key, md_json_t *json)
     return 1;
 }
 
-static void print_job_summary(apr_bucket_brigade *bb, md_json_t *mdj, const char *key, 
+static void print_job_summary(status_ctx *ctx, md_json_t *mdj, const char *key,
                               const char *separator)
 {
+    apr_bucket_brigade *bb = ctx->bb;
     char buffer[HUGE_STRING_LEN];
     apr_status_t rv;
     int finished, errors, cert_count;
     apr_time_t t;
     const char *s, *line;
-    
+
     if (!md_json_has_key(mdj, key, NULL)) {
         return;
     }
-    
+
     finished = md_json_getb(mdj, key, MD_KEY_FINISHED, NULL);
     errors = (int)md_json_getl(mdj, key, MD_KEY_ERRORS, NULL);
     rv = (apr_status_t)md_json_getl(mdj, key, MD_KEY_LAST, MD_KEY_STATUS, NULL);
-    
+
     line = separator? separator : "";
 
     if (rv != APR_SUCCESS) {
+        char *errstr = apr_strerror(rv, buffer, sizeof(buffer));
         s = md_json_gets(mdj, key, MD_KEY_LAST, MD_KEY_PROBLEM, NULL);
-        line = apr_psprintf(bb->p, "%s Error[%s]: %s", line, 
-                           apr_strerror(rv, buffer, sizeof(buffer)), s? s : "");
+        if (HTML_STATUS(ctx)) {
+            line = apr_psprintf(bb->p, "%s Error[%s]: %s", line,
+                                errstr, s? s : "");
+        }
+        else {
+            apr_brigade_printf(bb, NULL, NULL, "%sLastStatus: %s\n", ctx->prefix, errstr);
+            apr_brigade_printf(bb, NULL, NULL, "%sLastProblem: %s\n", ctx->prefix, s);
+        }
+    }
+
+    if (!HTML_STATUS(ctx)) {
+        apr_brigade_printf(bb, NULL, NULL, "%sFinished: %s\n", ctx->prefix,
+                           finished ? "yes" : "no");
     }
-    
     if (finished) {
         cert_count = 0;
         md_json_iterkey(count_certs, &cert_count, mdj, key, MD_KEY_CERT, NULL);
-        if (cert_count > 0) {
-            line =apr_psprintf(bb->p, "%s  finished, %d new certificate%s staged.",
-                               line, cert_count, cert_count > 1? "s" : "");
+        if (HTML_STATUS(ctx)) {
+            if (cert_count > 0) {
+                line =apr_psprintf(bb->p, "%s  finished, %d new certificate%s staged.",
+                                   line, cert_count, cert_count > 1? "s" : "");
+            }
+            else {
+                line = apr_psprintf(bb->p, "%s  finished successfully.", line);
+            }
         }
         else {
-            line = apr_psprintf(bb->p, "%s  finished successfully.", line);
+            apr_brigade_printf(bb, NULL, NULL, "%sNewStaged: %d\n", ctx->prefix, cert_count);
         }
     }
     else {
         s = md_json_gets(mdj, key, MD_KEY_LAST, MD_KEY_DETAIL, NULL);
-        if (s) line = apr_psprintf(bb->p, "%s %s", line, s);
+        if (s) {
+            if (HTML_STATUS(ctx)) {
+                line = apr_psprintf(bb->p, "%s %s", line, s);
+            }
+            else {
+                apr_brigade_printf(bb, NULL, NULL, "%sLastDetail: %s\n", ctx->prefix, s);
+            }
+        }
     }
-    
+
     errors = (int)md_json_getl(mdj, MD_KEY_ERRORS, NULL);
     if (errors > 0) {
-        line = apr_psprintf(bb->p, "%s (%d retr%s) ", line, 
-            errors, (errors > 1)? "y" : "ies");
-    } 
-    
-    apr_brigade_puts(bb, NULL, NULL, line);
+        if (HTML_STATUS(ctx)) {
+            line = apr_psprintf(bb->p, "%s (%d retr%s) ", line,
+                                errors, (errors > 1)? "y" : "ies");
+        }
+        else {
+            apr_brigade_printf(bb, NULL, NULL, "%sRetries: %d\n", ctx->prefix, errors);
+        }
+    }
+
+    if (HTML_STATUS(ctx)) {
+        apr_brigade_puts(bb, NULL, NULL, line);
+    }
 
     t = md_json_get_time(mdj, key, MD_KEY_NEXT_RUN, NULL);
     if (t > apr_time_now() && !finished) {
-        print_time(bb, "\nNext run", t);
+        print_time(ctx,
+                   HTML_STATUS(ctx) ? "\nNext run" : "NextRun",
+                   t);
     }
-    else if (!strlen(line)) {
-        apr_brigade_puts(bb, NULL, NULL, "\nOngoing...");
+    else if (line[0] != '\0') {
+        if (HTML_STATUS(ctx)) {
+            apr_brigade_puts(bb, NULL, NULL, "\nOngoing...");
+        }
+        else {
+            apr_brigade_printf(bb, NULL, NULL, "%s: Ongoing\n", ctx->prefix);
+        }
     }
 }
 
 static void si_val_activity(status_ctx *ctx, md_json_t *mdj, const status_info *info)
 {
     apr_time_t t;
-    
+    const char *prefix = ctx->prefix;
+
     (void)info;
+    if (!HTML_STATUS(ctx)) {
+        ctx->prefix = apr_pstrcat(ctx->p, prefix, info->label, NULL);
+    }
+
     if (md_json_has_key(mdj, MD_KEY_RENEWAL, NULL)) {
-        print_job_summary(ctx->bb, mdj, MD_KEY_RENEWAL, NULL);
+        print_job_summary(ctx, mdj, MD_KEY_RENEWAL, NULL);
         return;
     }
-    
+
     t = md_json_get_time(mdj, MD_KEY_RENEW_AT, NULL);
     if (t > apr_time_now()) {
-        print_time(ctx->bb, "Renew", t);
+        print_time(ctx, "Renew", t);
     }
     else if (t) {
-        apr_brigade_puts(ctx->bb, NULL, NULL, "Pending");
+        if (HTML_STATUS(ctx)) {
+            apr_brigade_puts(ctx->bb, NULL, NULL, "Pending");
+        }
+        else {
+            apr_brigade_printf(ctx->bb, NULL, NULL, "%s: %s", ctx->prefix, "Pending");
+        }
     }
     else if (MD_RENEW_MANUAL == md_json_getl(mdj, MD_KEY_RENEW_MODE, NULL)) {
-        apr_brigade_puts(ctx->bb, NULL, NULL, "Manual renew");
+        if (HTML_STATUS(ctx)) {
+            apr_brigade_puts(ctx->bb, NULL, NULL, "Manual renew");
+        }
+        else {
+            apr_brigade_printf(ctx->bb, NULL, NULL, "%s: %s", ctx->prefix, "Manual renew");
+        }
+    }
+    if (!HTML_STATUS(ctx)) {
+        ctx->prefix = prefix;
     }
 }
 
@@ -408,13 +510,33 @@ static int cert_check_iter(void *baton, const char *key, md_json_t *json)
 {
     status_ctx *ctx = baton;
     const char *fingerprint;
-    
+
     fingerprint = md_json_gets(json, MD_KEY_SHA256_FINGERPRINT, NULL);
     if (fingerprint) {
-        apr_brigade_printf(ctx->bb, NULL, NULL, 
-                           "<a href=\"%s%s\">%s[%s]</a><br>", 
-                           ctx->mc->cert_check_url, fingerprint, 
-                           ctx->mc->cert_check_name, key);
+        if (HTML_STATUS(ctx)) {
+            apr_brigade_printf(ctx->bb, NULL, NULL,
+                               "<a href=\"%s%s\">%s[%s]</a><br>",
+                               ctx->mc->cert_check_url, fingerprint,
+                               ctx->mc->cert_check_name, key);
+        }
+        else {
+            apr_brigade_printf(ctx->bb, NULL, NULL,
+                               "%sType: %s\n",
+                               ctx->prefix,
+                               key);
+            apr_brigade_printf(ctx->bb, NULL, NULL,
+                               "%sName: %s\n",
+                               ctx->prefix,
+                               ctx->mc->cert_check_name);
+            apr_brigade_printf(ctx->bb, NULL, NULL,
+                               "%sURL: %s%s\n",
+                               ctx->prefix,
+                               ctx->mc->cert_check_url, fingerprint);
+            apr_brigade_printf(ctx->bb, NULL, NULL,
+                               "%sFingerprint: %s\n",
+                               ctx->prefix,
+                               fingerprint);
+        }
     }
     return 1;
 }
@@ -423,7 +545,14 @@ static void si_val_remote_check(status_ctx *ctx, md_json_t *mdj, const status_in
 {
     (void)info;
     if (ctx->mc->cert_check_name && ctx->mc->cert_check_url) {
+        const char *prefix = ctx->prefix;
+        if (!HTML_STATUS(ctx)) {
+            ctx->prefix = apr_pstrcat(ctx->p, prefix, info->label, NULL);
+        }
         md_json_iterkey(cert_check_iter, ctx, mdj, MD_KEY_CERT, NULL);
+        if (!HTML_STATUS(ctx)) {
+            ctx->prefix = prefix;
+        }
     }
 }
 
@@ -431,24 +560,43 @@ static void si_val_stapling(status_ctx *ctx, md_json_t *mdj, const status_info *
 {
     (void)info;
     if (!md_json_getb(mdj, MD_KEY_STAPLING, NULL)) return;
-    apr_brigade_puts(ctx->bb, NULL, NULL, "on");
+    if (HTML_STATUS(ctx)) {
+        apr_brigade_puts(ctx->bb, NULL, NULL, "on");
+    }
+    else {
+        apr_brigade_printf(ctx->bb, NULL, NULL, "%s: on", ctx->prefix);
+    }
 }
 
 static int json_iter_val(void *data, size_t index, md_json_t *json)
 {
     status_ctx *ctx = data;
-    if (index) apr_brigade_puts(ctx->bb, NULL, NULL, ctx->separator);
+    const char *prefix = ctx->prefix;
+    if (HTML_STATUS(ctx)) {
+        if (index) apr_brigade_puts(ctx->bb, NULL, NULL, ctx->separator);
+    }
+    else {
+        ctx->prefix = apr_pstrcat(ctx->p, prefix, apr_psprintf(ctx->p, "[%" APR_SIZE_T_FMT "]", index), NULL);
+    }
     add_json_val(ctx, json);
+    if (!HTML_STATUS(ctx)) {
+        ctx->prefix = prefix;
+    }
     return 1;
 }
 
 static void add_json_val(status_ctx *ctx, md_json_t *j)
 {
     if (!j) return;
-    else if (md_json_is(MD_JSON_TYPE_ARRAY, j, NULL)) {
+    if (md_json_is(MD_JSON_TYPE_ARRAY, j, NULL)) {
         md_json_itera(json_iter_val, ctx, j, NULL);
+        return;
     }
-    else if (md_json_is(MD_JSON_TYPE_INT, j, NULL)) {
+    if (!HTML_STATUS(ctx)) {
+        apr_brigade_puts(ctx->bb, NULL, NULL, ctx->prefix);
+        apr_brigade_puts(ctx->bb, NULL, NULL, ": ");
+    }
+    if (md_json_is(MD_JSON_TYPE_INT, j, NULL)) {
         md_json_writeb(j, MD_JSON_FMT_COMPACT, ctx->bb);
     }
     else if (md_json_is(MD_JSON_TYPE_STRING, j, NULL)) {
@@ -460,13 +608,27 @@ static void add_json_val(status_ctx *ctx, md_json_t *j)
     else if (md_json_is(MD_JSON_TYPE_BOOL, j, NULL)) {
         apr_brigade_puts(ctx->bb, NULL, NULL, md_json_getb(j, NULL)? "on" : "off");
     }
+    if (!HTML_STATUS(ctx)) {
+        apr_brigade_puts(ctx->bb, NULL, NULL, "\n");
+    }
 }
 
 static void si_val_names(status_ctx *ctx, md_json_t *mdj, const status_info *info)
 {
-    apr_brigade_puts(ctx->bb, NULL, NULL, "<div style=\"max-width:400px;\">");
+    const char *prefix = ctx->prefix;
+    if (HTML_STATUS(ctx)) {
+        apr_brigade_puts(ctx->bb, NULL, NULL, "<div style=\"max-width:400px;\">");
+    }
+    else {
+        ctx->prefix = apr_pstrcat(ctx->p, prefix, info->label, NULL);
+    }
     add_json_val(ctx, md_json_getj(mdj, info->key, NULL));
-    apr_brigade_puts(ctx->bb, NULL, NULL, "</div>");
+    if (HTML_STATUS(ctx)) {
+        apr_brigade_puts(ctx->bb, NULL, NULL, "</div>");
+    }
+    else {
+        ctx->prefix = prefix;
+    }
 }
 
 static void add_status_cell(status_ctx *ctx, md_json_t *mdj, const status_info *info)
@@ -475,7 +637,14 @@ static void add_status_cell(status_ctx *ctx, md_json_t *mdj, const status_info *
         info->fn(ctx, mdj, info);
     }
     else {
+        const char *prefix = ctx->prefix;
+        if (!HTML_STATUS(ctx)) {
+            ctx->prefix = apr_pstrcat(ctx->p, prefix, info->label, NULL);
+        }
         add_json_val(ctx, md_json_getj(mdj, info->key, NULL));
+        if (!HTML_STATUS(ctx)) {
+            ctx->prefix = prefix;
+        }
     }
 }
 
@@ -486,22 +655,31 @@ static const status_info status_infos[] = {
     { "Valid", MD_KEY_CERT, si_val_cert_valid_time },
     { "CA", MD_KEY_CA, si_val_ca_url },
     { "Stapling", MD_KEY_STAPLING, si_val_stapling },
-    { "Check@", MD_KEY_SHA256_FINGERPRINT, si_val_remote_check },
-    { "Activity",  MD_KEY_NOTIFIED, si_val_activity },
+    { "CheckAt", MD_KEY_SHA256_FINGERPRINT, si_val_remote_check },
+    { "Activity", MD_KEY_NOTIFIED, si_val_activity },
 };
 
 static int add_md_row(void *baton, apr_size_t index, md_json_t *mdj)
 {
     status_ctx *ctx = baton;
+    const char *prefix = ctx->prefix;
     int i;
-    
-    apr_brigade_printf(ctx->bb, NULL, NULL, "<tr class=\"%s\">", (index % 2)? "odd" : "even");
-    for (i = 0; i < (int)(sizeof(status_infos)/sizeof(status_infos[0])); ++i) {
-        apr_brigade_puts(ctx->bb, NULL, NULL, "<td>");
-        add_status_cell(ctx, mdj, &status_infos[i]);
-        apr_brigade_puts(ctx->bb, NULL, NULL, "</td>");
-    }
-    apr_brigade_puts(ctx->bb, NULL, NULL, "</tr>");
+
+    if (HTML_STATUS(ctx)) {
+        apr_brigade_printf(ctx->bb, NULL, NULL, "<tr class=\"%s\">", (index % 2)? "odd" : "even");
+        for (i = 0; i < (int)(sizeof(status_infos)/sizeof(status_infos[0])); ++i) {
+            apr_brigade_puts(ctx->bb, NULL, NULL, "<td>");
+            add_status_cell(ctx, mdj, &status_infos[i]);
+            apr_brigade_puts(ctx->bb, NULL, NULL, "</td>");
+        }
+        apr_brigade_puts(ctx->bb, NULL, NULL, "</tr>");
+    } else {
+        for (i = 0; i < (int)(sizeof(status_infos)/sizeof(status_infos[0])); ++i) {
+            ctx->prefix = apr_pstrcat(ctx->p, prefix, apr_psprintf(ctx->p, "[%" APR_SIZE_T_FMT "]", index), NULL);
+            add_status_cell(ctx, mdj, &status_infos[i]);
+            ctx->prefix = prefix;
+        }
+    }
     return 1;
 }
 
@@ -514,96 +692,121 @@ int md_domains_status_hook(request_rec *r, int flags)
 {
     const md_srv_conf_t *sc;
     const md_mod_conf_t *mc;
-    int i, html;
+    int i;
     status_ctx ctx;
     apr_array_header_t *mds;
     md_json_t *jstatus, *jstock;
-    
+
     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "server-status for managed domains, start");
     sc = ap_get_module_config(r->server->module_config, &md_module);
     if (!sc) return DECLINED;
     mc = sc->mc;
     if (!mc || !mc->server_status_enabled) return DECLINED;
 
-    html = !(flags & AP_STATUS_SHORT);
     ctx.p = r->pool;
     ctx.mc = mc;
     ctx.bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+    ctx.flags = flags;
+    ctx.prefix = "ManagedCertificates";
     ctx.separator = " ";
 
     mds = apr_array_copy(r->pool, mc->mds);
     qsort(mds->elts, (size_t)mds->nelts, sizeof(md_t *), md_name_cmp);
 
-    if (!html) {
-        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "no-html summary");
-        apr_brigade_puts(ctx.bb, NULL, NULL, "Managed Certificates: ");
+    if (!HTML_STATUS(&ctx)) {
+        int total = 0, complete = 0, renewing = 0, errored = 0, ready = 0;
+        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "no-html managed domain status summary");
         if (mc->mds->nelts > 0) {
             md_status_take_stock(&jstock, mds, mc->reg, r->pool);
-            ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "got JSON summary");
-            apr_brigade_printf(ctx.bb, NULL, NULL, "total=%d, ok=%d renew=%d errored=%d ready=%d",
-                                (int)md_json_getl(jstock, MD_KEY_TOTAL, NULL), 
-                                (int)md_json_getl(jstock, MD_KEY_COMPLETE, NULL), 
-                                (int)md_json_getl(jstock, MD_KEY_RENEWING, NULL), 
-                                (int)md_json_getl(jstock, MD_KEY_ERRORED, NULL), 
-                                (int)md_json_getl(jstock, MD_KEY_READY, NULL));
-        } 
-        else {
-            apr_brigade_puts(ctx.bb, NULL, NULL, "[]"); 
+            ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "got JSON managed domain status summary");
+            total = (int)md_json_getl(jstock, MD_KEY_TOTAL, NULL);
+            complete = (int)md_json_getl(jstock, MD_KEY_COMPLETE, NULL);
+            renewing = (int)md_json_getl(jstock, MD_KEY_RENEWING, NULL);
+            errored = (int)md_json_getl(jstock, MD_KEY_ERRORED, NULL);
+            ready = (int)md_json_getl(jstock, MD_KEY_READY, NULL);
         }
-        apr_brigade_puts(ctx.bb, NULL, NULL, "\n"); 
+        apr_brigade_printf(ctx.bb, NULL, NULL, "%sTotal: %d\n", ctx.prefix, total);
+        apr_brigade_printf(ctx.bb, NULL, NULL, "%sOK: %d\n", ctx.prefix, complete);
+        apr_brigade_printf(ctx.bb, NULL, NULL, "%sRenew: %d\n", ctx.prefix, renewing);
+        apr_brigade_printf(ctx.bb, NULL, NULL, "%sErrored: %d\n", ctx.prefix, errored);
+        apr_brigade_printf(ctx.bb, NULL, NULL, "%sReady: %d\n", ctx.prefix, ready);
     }
-    else if (mc->mds->nelts > 0) {
-        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "html table");
+    if (mc->mds->nelts > 0) {
         md_status_get_json(&jstatus, mds, mc->reg, mc->ocsp, r->pool);
-        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "got JSON status");
-        apr_brigade_puts(ctx.bb, NULL, NULL, 
-                         "<hr>\n<h3>Managed Certificates</h3>\n<table class='md_status'><thead><tr>\n");
-        for (i = 0; i < (int)(sizeof(status_infos)/sizeof(status_infos[0])); ++i) {
-            si_add_header(&ctx, &status_infos[i]);
+        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "got JSON managed domain status");
+        if (HTML_STATUS(&ctx)) {
+            ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "html managed domain status table");
+            apr_brigade_puts(ctx.bb, NULL, NULL,
+                             "<hr>\n<h3>Managed Certificates</h3>\n<table class='md_status'><thead><tr>\n");
+            for (i = 0; i < (int)(sizeof(status_infos)/sizeof(status_infos[0])); ++i) {
+                si_add_header(&ctx, &status_infos[i]);
+            }
+            apr_brigade_puts(ctx.bb, NULL, NULL, "</tr>\n</thead><tbody>");
         }
-        apr_brigade_puts(ctx.bb, NULL, NULL, "</tr>\n</thead><tbody>");
+        else {
+            ctx.prefix = "ManagedDomain";
+        }
+        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "iterating JSON managed domain status");
         md_json_itera(add_md_row, &ctx, jstatus, MD_KEY_MDS, NULL);
-        apr_brigade_puts(ctx.bb, NULL, NULL, "</td></tr>\n</tbody>\n</table>\n");
+        if (HTML_STATUS(&ctx)) {
+            apr_brigade_puts(ctx.bb, NULL, NULL, "</td></tr>\n</tbody>\n</table>\n");
+        }
     }
 
     ap_pass_brigade(r->output_filters, ctx.bb);
     apr_brigade_cleanup(ctx.bb);
     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "server-status for managed domains, end");
-    
+
     return OK;
 }
 
 static void si_val_ocsp_activity(status_ctx *ctx, md_json_t *mdj, const status_info *info)
 {
     apr_time_t t;
-    
+    const char *prefix = ctx->prefix;
+
     (void)info;
-    t = md_json_get_time(mdj,  MD_KEY_RENEW_AT, NULL);
-    print_time(ctx->bb, "Refresh", t);
-    print_job_summary(ctx->bb, mdj, MD_KEY_RENEWAL, ": ");
+    if (!HTML_STATUS(ctx)) {
+        ctx->prefix = apr_pstrcat(ctx->p, prefix, info->label, NULL);
+    }
+    t = md_json_get_time(mdj, MD_KEY_RENEW_AT, NULL);
+    print_time(ctx, "Refresh", t);
+    print_job_summary(ctx, mdj, MD_KEY_RENEWAL, ": ");
+    if (!HTML_STATUS(ctx)) {
+        ctx->prefix = prefix;
+    }
 }
 
 static const status_info ocsp_status_infos[] = {
     { "Domain", MD_KEY_DOMAIN, NULL },
-    { "Certificate ID", MD_KEY_ID, NULL },
-    { "OCSP Status", MD_KEY_STATUS, NULL },
-    { "Stapling Valid", MD_KEY_VALID, si_val_valid_time },
+    { "CertificateID", MD_KEY_ID, NULL },
+    { "OCSPStatus", MD_KEY_STATUS, NULL },
+    { "StaplingValid", MD_KEY_VALID, si_val_valid_time },
     { "Responder", MD_KEY_URL, si_val_url },
-    { "Activity",  MD_KEY_NOTIFIED, si_val_ocsp_activity },
+    { "Activity", MD_KEY_NOTIFIED, si_val_ocsp_activity },
 };
 
 static int add_ocsp_row(void *baton, apr_size_t index, md_json_t *mdj)
 {
     status_ctx *ctx = baton;
+    const char *prefix = ctx->prefix;
     int i;
-    
-    apr_brigade_printf(ctx->bb, NULL, NULL, "<tr class=\"%s\">", (index % 2)? "odd" : "even");
-    for (i = 0; i < (int)(sizeof(ocsp_status_infos)/sizeof(ocsp_status_infos[0])); ++i) {
-        apr_brigade_puts(ctx->bb, NULL, NULL, "<td>");
-        add_status_cell(ctx, mdj, &ocsp_status_infos[i]);
-        apr_brigade_puts(ctx->bb, NULL, NULL, "</td>");
-    }
-    apr_brigade_puts(ctx->bb, NULL, NULL, "</tr>");
+
+    if (HTML_STATUS(ctx)) {
+        apr_brigade_printf(ctx->bb, NULL, NULL, "<tr class=\"%s\">", (index % 2)? "odd" : "even");
+        for (i = 0; i < (int)(sizeof(ocsp_status_infos)/sizeof(ocsp_status_infos[0])); ++i) {
+            apr_brigade_puts(ctx->bb, NULL, NULL, "<td>");
+            add_status_cell(ctx, mdj, &ocsp_status_infos[i]);
+            apr_brigade_puts(ctx->bb, NULL, NULL, "</td>");
+        }
+        apr_brigade_puts(ctx->bb, NULL, NULL, "</tr>");
+    } else {
+        for (i = 0; i < (int)(sizeof(ocsp_status_infos)/sizeof(ocsp_status_infos[0])); ++i) {
+            ctx->prefix = apr_pstrcat(ctx->p, prefix, apr_psprintf(ctx->p, "[%" APR_SIZE_T_FMT "]", index), NULL);
+            add_status_cell(ctx, mdj, &ocsp_status_infos[i]);
+            ctx->prefix = prefix;
+        }
+    }
     return 1;
 }
 
@@ -611,53 +814,65 @@ int md_ocsp_status_hook(request_rec *r, int flags)
 {
     const md_srv_conf_t *sc;
     const md_mod_conf_t *mc;
-    int i, html;
+    int i;
     status_ctx ctx;
     md_json_t *jstatus, *jstock;
-    
+
     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "server-status for ocsp stapling, start");
     sc = ap_get_module_config(r->server->module_config, &md_module);
     if (!sc) return DECLINED;
     mc = sc->mc;
     if (!mc || !mc->server_status_enabled) return DECLINED;
 
-    html = !(flags & AP_STATUS_SHORT);
     ctx.p = r->pool;
     ctx.mc = mc;
     ctx.bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
+    ctx.flags = flags;
+    ctx.prefix = "ManagedStaplings";
     ctx.separator = " ";
 
-    if (!html) {
-        apr_brigade_puts(ctx.bb, NULL, NULL, "Managed Staplings: ");
+    if (!HTML_STATUS(&ctx)) {
+        int total = 0, good = 0, revoked = 0, unknown = 0;
+        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "no-html ocsp stapling status summary");
         if (md_ocsp_count(mc->ocsp) > 0) {
             md_ocsp_get_summary(&jstock, mc->ocsp, r->pool);
-            apr_brigade_printf(ctx.bb, NULL, NULL, "total=%d, good=%d revoked=%d unknown=%d",
-                                (int)md_json_getl(jstock, MD_KEY_TOTAL, NULL), 
-                                (int)md_json_getl(jstock, MD_KEY_GOOD, NULL), 
-                                (int)md_json_getl(jstock, MD_KEY_REVOKED, NULL), 
-                                (int)md_json_getl(jstock, MD_KEY_UNKNOWN, NULL));
-        } 
-        else {
-            apr_brigade_puts(ctx.bb, NULL, NULL, "[]"); 
+            ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "got JSON ocsp stapling status summary");
+            total = (int)md_json_getl(jstock, MD_KEY_TOTAL, NULL);
+            good = (int)md_json_getl(jstock, MD_KEY_GOOD, NULL);
+            revoked = (int)md_json_getl(jstock, MD_KEY_REVOKED, NULL);
+            unknown = (int)md_json_getl(jstock, MD_KEY_UNKNOWN, NULL);
         }
-        apr_brigade_puts(ctx.bb, NULL, NULL, "\n"); 
+        apr_brigade_printf(ctx.bb, NULL, NULL, "%sTotal: %d\n", ctx.prefix, total);
+        apr_brigade_printf(ctx.bb, NULL, NULL, "%sOK: %d\n", ctx.prefix, good);
+        apr_brigade_printf(ctx.bb, NULL, NULL, "%sRenew: %d\n", ctx.prefix, revoked);
+        apr_brigade_printf(ctx.bb, NULL, NULL, "%sErrored: %d\n", ctx.prefix, unknown);
     }
-    else if (md_ocsp_count(mc->ocsp) > 0) {
+    if (md_ocsp_count(mc->ocsp) > 0) {
         md_ocsp_get_status_all(&jstatus, mc->ocsp, r->pool);
-        apr_brigade_puts(ctx.bb, NULL, NULL, 
-                         "<hr>\n<h3>Managed Staplings</h3>\n<table class='md_ocsp_status'><thead><tr>\n");
-        for (i = 0; i < (int)(sizeof(ocsp_status_infos)/sizeof(ocsp_status_infos[0])); ++i) {
-            si_add_header(&ctx, &ocsp_status_infos[i]);
+        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "got JSON ocsp stapling status");
+        if (HTML_STATUS(&ctx)) {
+            ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "html ocsp stapling status table");
+            apr_brigade_puts(ctx.bb, NULL, NULL,
+                             "<hr>\n<h3>Managed Staplings</h3>\n<table class='md_ocsp_status'><thead><tr>\n");
+            for (i = 0; i < (int)(sizeof(ocsp_status_infos)/sizeof(ocsp_status_infos[0])); ++i) {
+                si_add_header(&ctx, &ocsp_status_infos[i]);
+            }
+            apr_brigade_puts(ctx.bb, NULL, NULL, "</tr>\n</thead><tbody>");
+        }
+        else {
+            ctx.prefix = "ManagedStapling";
         }
-        apr_brigade_puts(ctx.bb, NULL, NULL, "</tr>\n</thead><tbody>");
+        ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "iterating JSON ocsp stapling status");
         md_json_itera(add_ocsp_row, &ctx, jstatus, MD_KEY_OCSPS, NULL);
-        apr_brigade_puts(ctx.bb, NULL, NULL, "</td></tr>\n</tbody>\n</table>\n");
+        if (HTML_STATUS(&ctx)) {
+            apr_brigade_puts(ctx.bb, NULL, NULL, "</td></tr>\n</tbody>\n</table>\n");
+        }
     }
 
     ap_pass_brigade(r->output_filters, ctx.bb);
     apr_brigade_cleanup(ctx.bb);
     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "server-status for ocsp stapling, end");
-    
+
     return OK;
 }
 
@@ -687,7 +902,7 @@ int md_status_handler(request_rec *r)
         ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "md-status supports only GET");
         return HTTP_NOT_IMPLEMENTED;
     }
-    
+
     jstatus = NULL;
     md = NULL;
     if (r->path_info && r->path_info[0] == '/' && r->path_info[1] != '\0') {
@@ -695,7 +910,7 @@ int md_status_handler(request_rec *r)
         md = md_get_by_name(mc->mds, name);
         if (!md) md = md_get_by_domain(mc->mds, name);
     }
-    
+
     if (md) {
         md_status_get_md_json(&jstatus, md, mc->reg, mc->ocsp, r->pool);
     }
@@ -706,12 +921,12 @@ int md_status_handler(request_rec *r)
     }
 
     if (jstatus) {
-        apr_table_set(r->headers_out, "Content-Type", "application/json"); 
+        apr_table_set(r->headers_out, "Content-Type", "application/json");
         bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
         md_json_writeb(jstatus, MD_JSON_FMT_INDENT, bb);
         ap_pass_brigade(r->output_filters, bb);
         apr_brigade_cleanup(bb);
-        
+
         return DONE;
     }
     return DECLINED;
index 36c520ac94b849af8f8d9e286ee811c6ef02ab29..c89ce6d8d7087a8febd68fd6fdbe709bc32989f2 100644 (file)
@@ -148,13 +148,17 @@ Protocols h2 http/1.1 acme-tls/1
         assert re.search(r'<h3>Managed Certificates</h3>', status, re.MULTILINE)
         # get the ascii summary
         status = env.get_server_status(query="?auto", via_domain=env.http_addr, use_https=False)
-        m = re.search(r'Managed Certificates: total=(\d+), ok=(\d+) renew=(\d+) errored=(\d+) ready=(\d+)',
-                      status, re.MULTILINE)
+        m = re.search(r'ManagedCertificatesTotal: (\d+)', status, re.MULTILINE)
+        assert m, status
+        assert int(m.group(1)) == 1
+        m = re.search(r'ManagedCertificatesOK: (\d+)', status, re.MULTILINE)
+        assert int(m.group(1)) == 0
+        m = re.search(r'ManagedCertificatesRenew: (\d+)', status, re.MULTILINE)
+        assert int(m.group(1)) == 1
+        m = re.search(r'ManagedCertificatesErrored: (\d+)', status, re.MULTILINE)
+        assert int(m.group(1)) == 0
+        m = re.search(r'ManagedCertificatesReady: (\d+)', status, re.MULTILINE)
         assert int(m.group(1)) == 1
-        assert int(m.group(2)) == 0
-        assert int(m.group(3)) == 1
-        assert int(m.group(4)) == 0
-        assert int(m.group(5)) == 1
 
     def test_md_920_011(self, env):
         # MD with static cert files in base server, see issue #161