diff options
Diffstat (limited to 'httpd.h')
-rw-r--r-- | httpd.h | 70 |
1 files changed, 61 insertions, 9 deletions
@@ -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 >%lu" "</title></head><body><p>mwrap each >%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 '?' */ |