about summary refs log tree commit homepage
path: root/httpd.h
diff options
context:
space:
mode:
Diffstat (limited to 'httpd.h')
-rw-r--r--httpd.h70
1 files changed, 61 insertions, 9 deletions
diff --git a/httpd.h b/httpd.h
index 9b4ebe7..fc7b873 100644
--- a/httpd.h
+++ b/httpd.h
@@ -41,6 +41,7 @@
 #define URL "https://80x24.org/mwrap-perl.git/about"
 #define TYPE_HTML "text/html; charset=UTF-8"
 #define TYPE_CSV "text/csv"
+#define TYPE_PLAIN "text/plain"
 
 enum mw_qev {
         MW_QEV_IGNORE = 0,
@@ -341,6 +342,15 @@ static enum mw_qev h1_do_trim(struct mw_h1 *h1)
         return h1_res_oneshot(h1, r200, sizeof(r200) - 1);
 }
 
+static enum mw_qev h1_do_ctl_finish(struct mw_h1 *h1)
+{
+        struct mw_fbuf plain;
+        FILE *fp = wbuf_init(&plain);
+        if (!fp) return h1_close(h1);
+        fprintf(fp, "MWRAP=bt:%u\n", (unsigned)CMM_LOAD_SHARED(bt_req_depth));
+        return h1_200(h1, &plain, TYPE_PLAIN);
+}
+
 #define PATH_SKIP(h1r, pfx) path_skip(h1r, pfx, sizeof(pfx) - 1)
 static const char *path_skip(struct mw_h1req *h1r, const char *pfx, size_t len)
 {
@@ -570,7 +580,7 @@ static enum mw_qev each_at(struct mw_h1 *h1, struct mw_h1req *h1r)
         FPUTS("<html><head><title>", fp);
         write_html(fp, lb.ptr, lb.len);
         FPUTS("</title></head><body><p>live allocations at:", fp);
-        if (bt_req_depth) FPUTS("<br/>", fp);
+        if (l->bt_len > 1 || (l->bt_len == 1 && l->f)) FPUTS("<br/>", fp);
         else fputc(' ', fp);
         write_html(fp, lb.ptr, lb.len);
 
@@ -627,13 +637,14 @@ static enum mw_qev each_gt(struct mw_h1 *h1, struct mw_h1req *h1r,
         if (!fp) return h1_close(h1);
 
         if (!csv) {
+                unsigned depth = (unsigned)CMM_LOAD_SHARED(bt_req_depth);
                 fprintf(fp, "<html><head><title>mwrap each &gt;%lu"
                         "</title></head><body><p>mwrap each &gt;%lu "
                         "(change `%lu' in URL to adjust filtering) - "
-                        "MWRAP=bt:%u", min, min, min, (unsigned)bt_req_depth);
+                        "MWRAP=bt:%u", min, min, min, depth);
                 show_stats(fp);
                 /* need borders to distinguish multi-level traces */
-                if (bt_req_depth)
+                if (depth)
                         FPUTS("<table\nborder=1><tr>", fp);
                 else /* save screen space if only tracing one line */
                         FPUTS("<table><tr>", fp);
@@ -757,6 +768,8 @@ static enum mw_qev h1_dispatch(struct mw_h1 *h1, struct mw_h1req *h1r)
                         return h1_do_reset(h1);
                 if (h1r->path_len == 5 && !memcmp(h1r->path, "/trim", 5))
                         return h1_do_trim(h1);
+                if (h1r->path_len == 4 && !memcmp(h1r->path, "/ctl", 4))
+                        return h1_do_ctl_finish(h1);
         }
         return h1_404(h1);
 }
@@ -816,12 +829,31 @@ static enum mw_qev h1_drain_input(struct mw_h1 *h1, struct mw_h1req *h1r)
         return h1_dispatch(h1, h1r);
 }
 
+static bool valid_end(const char *end)
+{
+        switch (*end) {
+        case '\r': case ' ': case '\t': case '\n': return true;
+        default: return false;
+        }
+}
+
+/* no error reporting, too much code */
+static void ctl_set(struct mw_h1 *h1, long n)
+{
+        if (n >= 0) {
+                if (n > MWRAP_BT_MAX)
+                        n = MWRAP_BT_MAX;
+                CMM_STORE_SHARED(bt_req_depth, (uint32_t)n);
+        }
+}
+
 static enum mw_qev h1_parse_harder(struct mw_h1 *h1, struct mw_h1req *h1r)
 {
         enum { HDR_IGN, HDR_CONN, HDR_XENC, HDR_CLEN } cur = HDR_IGN;
         bool conn_set = false;
         char *end;
         struct phr_header *hdr = h1r->hdr;
+        long depth = -1;
 
         h1->prev_len = 0;
         h1->has_input = 0;
@@ -837,8 +869,21 @@ static enum mw_qev h1_parse_harder(struct mw_h1 *h1, struct mw_h1req *h1r)
                         cur = HDR_CONN;
                 else if (NAME_EQ(hdr, "Trailer"))
                         return h1_400(h1);
-                else if (hdr->name)
+                else if (hdr->name) {
                         cur = HDR_IGN;
+                        /*
+                         * don't want to increase code to deal with POST
+                         * request bodies, so let pico handle parameters in
+                         * HTTP request headers, instead.
+                         */
+                        if (NAME_EQ(hdr, "X-Mwrap-BT-Depth")) {
+                                errno = 0;
+                                depth = strtol(hdr->value, &end, 10);
+                                if (errno || !valid_end(end))
+                                        depth = -1;
+                        }
+                }
+
                 /* else: continuation line */
                 if (!hdr->value_len)
                         continue;
@@ -860,12 +905,8 @@ static enum mw_qev h1_parse_harder(struct mw_h1 *h1, struct mw_h1req *h1r)
                         h1->has_input = 1;
                         errno = 0;
                         h1->in_len = strtoul(hdr->value, &end, 10);
-                        if (errno)
+                        if (errno || !valid_end(end))
                                 return h1_400(h1);
-                        switch (*end) {
-                        case '\r': case ' ': case '\t': case '\n': break;
-                        default: return h1_400(h1);
-                        }
                         break;
                 case HDR_IGN:
                         break;
@@ -883,6 +924,17 @@ static enum mw_qev h1_parse_harder(struct mw_h1 *h1, struct mw_h1req *h1r)
         } else {
                 return h1_404(h1);
         }
+
+        /*
+         * special case for /ctl, since I don't feel like parsing queries
+         * in the request body (ensure no query string, too)
+         */
+        if (h1r->method_len == 4 && !memcmp(h1r->method, "POST", 4)) {
+                if (h1r->path_len == 4 && !memcmp(h1r->path, "/ctl", 4))
+                        ctl_set(h1, depth);
+        }
+
+        /* break off QUERY_STRING */
         h1r->qstr = memchr(h1r->path, '?', h1r->path_len);
         if (h1r->qstr) {
                 ++h1r->qstr; /* ignore '?' */