diff options
Diffstat (limited to 'mwrap_httpd.h')
-rw-r--r-- | mwrap_httpd.h | 166 |
1 files changed, 92 insertions, 74 deletions
diff --git a/mwrap_httpd.h b/mwrap_httpd.h index bfa723d..bd37fb2 100644 --- a/mwrap_httpd.h +++ b/mwrap_httpd.h @@ -102,6 +102,7 @@ struct h1_src_loc { size_t live; size_t max_life; off_t lname_len; + const struct src_loc *sl; char *loc_name; }; @@ -333,76 +334,76 @@ static void write_html(FILE *fp, const char *s, size_t len) } } -static void write_uri(FILE *fp, const char *s, size_t len) +/* URI-safe base-64 (RFC 4648) */ +static void write_b64_url(FILE *fp, const uint8_t *in, size_t len) { -#define CGI_URI_OK(x) \ - ((x >= 'a' && x <= 'z') || \ - (x >= 'A' && x <= 'Z') || \ - (x >= '0' && x <= '9') || \ - (x == '.' || x == '-' || x == '_' || x == '~')) - for (; len--; ++s) { - if (caa_likely(CGI_URI_OK(*s))) { - fputc(*s, fp); - } else { - static const char cgi_digitmap[] = "0123456789ABCDEF"; - unsigned char c = *s; - char x[3]; - - x[2] = cgi_digitmap[(c % 16)]; - x[1] = cgi_digitmap[((c / 16) % 16)]; - x[0] = '%'; - fwrite(x, sizeof(x), 1, fp); - } + static const uint8_t b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" "0123456789-_"; + uint8_t o[4]; + while (len > 3) { + o[0] = b64[(in[0] >> 2) & 0x3f]; + o[1] = b64[((in[0] << 4) | (in[1] >> 4)) & 0x3f]; + o[2] = b64[((in[1] << 2) | (in[2] >> 6)) & 0x3f]; + o[3] = b64[in[2] & 0x3f]; + fwrite(o, sizeof(o), 1, fp); + len -= 3; + in += 3; + } + if (len) { + size_t i = 2; + + o[0] = b64[(in[0] >> 2) & 0x3f]; + o[1] = b64[((in[0] << 4) | (--len ? (in[1] >> 4) : 0)) & 0x3f]; + if (len) + o[i++] = b64[((in[1] << 2) | + (--len ? in[2] >> 6 : 0)) & 0x3f]; + if (len) + o[i++] = b64[in[2] & 0x3f]; + fwrite(o, i, 1, fp); } -#undef CGI_URI_OK -} - -static bool is_hex(int x) -{ - return (((x) >= '0' && (x) <= '9') || - ((x) >= 'a' && (x) <= 'f') || - ((x) >= 'A' && (x) <= 'F')); -} - -static int xtoupper(int x) -{ - return (x >= 'a' && x <= 'f') ? (x & ~0x20) : x; -} - -static int hexchar_to_int(int x) -{ - return (x < 'A') ? (x - '0') : (xtoupper(x) - 'A' + 10); -} - -static int hexpair_to_int(int x1, int x2) -{ - return ((hexchar_to_int(x1) << 4) | hexchar_to_int(x2)); } /* unescapes @s in-place and adjusts @len */ -static const char *uri_unescape(const char *s, size_t *len) +static bool b64_url_decode(const void *ptr, size_t *len) { - union { const char *in; char *out; } deconst; - size_t orig = *len; - char *out; - - deconst.in = s; - out = deconst.out; - for (; orig--; s++) { - if (caa_unlikely(*s == '%') && orig > 1 && - caa_likely(is_hex(s[1])) && - caa_likely(is_hex(s[2]))) { - orig -= 2; - *len -= 2; - *out++ = hexpair_to_int(s[1], s[2]); - s += 2; - } else { - *out++ = *s; + union { const void *in; uint8_t *out; } deconst; + const uint8_t *in = ptr; + uint8_t u = 0; + + deconst.in = ptr; + uint8_t *out = deconst.out; + + for (size_t i = 0; i < *len; ++i) { + uint8_t c = in[i]; + + switch (c) { + case 'A' ... 'Z': c -= 'A'; break; + case 'a' ... 'z': c -= ('a' - 26); break; + case '0' ... '9': c -= ('0' - 52); break; + case '-': c = 62; break; + case '_': c = 63; break; + default: return false; + } + + mwrap_assert(c <= 63); + switch (i % 4) { + case 0: u = c << 2; break; + case 1: + *out++ = u | c >> 4; + u = (c & 0xf) << 4; + break; + case 2: + *out++ = u | c >> 2; + u = (c & 0x3) << 6; + break; + case 3: *out++ = u | c; } } - return deconst.in; + *len = out - in; + return true; } +/* keep this consistent with Mwrap.xs location_string */ static off_t write_loc_name(FILE *fp, const struct src_loc *l) { off_t beg = ftello(fp); @@ -417,12 +418,21 @@ static off_t write_loc_name(FILE *fp, const struct src_loc *l) FPUTS(":-", fp); else fprintf(fp, ":%zu", l->lineno); - } else { + } + if (l->bt_len) { char **s = bt_syms(l->bt, l->bt_len); if (!s) return -1; + if (l->f) fputc('\n', fp); + + /* omit local " [$ADDRESS]" if doing deep backtraces */ + for (uint32_t i = 0; i < l->bt_len; ++i) { + char *c = memrchr(s[i], '[', strlen(s[i])); + if (c && c > (s[i] + 2) && c[-1] == ' ') + c[-1] = '\0'; + } fputs(s[0], fp); - for (uint32_t i = 1; i < l->bt_len; i++) { + for (uint32_t i = 1; i < l->bt_len; ++i) { fputc('\n', fp); fputs(s[i], fp); } @@ -445,7 +455,6 @@ static struct h1_src_loc *accumulate(unsigned long min, size_t *hslc, FILE *lp) struct cds_lfht *t = CMM_LOAD_SHARED(totals); struct cds_lfht_iter iter; struct src_loc *l; - ++locating; if (t) cds_lfht_for_each_entry(t, &iter, l, hnode) { size_t freed = uatomic_read(&l->freed_bytes); size_t total = uatomic_read(&l->total); @@ -461,11 +470,10 @@ static struct h1_src_loc *accumulate(unsigned long min, size_t *hslc, FILE *lp) (long double)hsl.frees) : HUGE_VAL; hsl.max_life = uatomic_read(&l->max_lifespan); + hsl.sl = l; hsl.lname_len = write_loc_name(lp, l); fwrite(&hsl, sizeof(hsl), 1, fp); } - --locating; - mwrap_assert(!locating); rcu_read_unlock(); struct h1_src_loc *hslv; @@ -486,9 +494,11 @@ static enum mw_qev each_at(struct mw_h1 *h1, struct mw_h1req *h1r) size_t len = h1r->path_len - (sizeof("/at/") - 1); size_t min = 0; - loc = uri_unescape(loc, &len); - if (len >= PATH_MAX) return h1_400(h1); - struct src_loc *l = mwrap_get(loc, len); + if (!b64_url_decode(loc, &len) || len >= PATH_MAX) + return h1_400(h1); + + struct src_loc *l = mwrap_get_bin(loc, len); + if (!l) return h1_404(h1); struct mw_membuf lname; @@ -503,7 +513,9 @@ static enum mw_qev each_at(struct mw_h1 *h1, struct mw_h1req *h1r) if (!fp) return h1_close(h1); FPUTS("<html><head><title>", fp); write_html(fp, lname.ptr, lname.len); - FPUTS("</title></head><body><p>live allocations at ", fp); + FPUTS("</title></head><body><p>live allocations at", fp); + if (bt_req_depth) FPUTS("<br/>", fp); + else fputc('\n', fp); write_html(fp, lname.ptr, lname.len); free(lname.ptr); @@ -514,7 +526,6 @@ static enum mw_qev each_at(struct mw_h1 *h1, struct mw_h1req *h1r) "<th>address</th></tr>", fp); rcu_read_lock(); - ++locating; struct alloc_hdr *h; cds_list_for_each_entry_rcu(h, &l->allocs, anode) { size_t size = uatomic_read(&h->size); @@ -522,8 +533,6 @@ static enum mw_qev each_at(struct mw_h1 *h1, struct mw_h1req *h1r) fprintf(fp, "<tr><td>%zu</td><td>%zu</td><td>%p</td>\n", size, h->as.live.gen, h->real); } - --locating; - mwrap_assert(!locating); rcu_read_unlock(); FPUTS("</table></body></html>", fp); return h1_200(h1, fp, &mb); @@ -574,7 +583,11 @@ static enum mw_qev each_gt(struct mw_h1 *h1, struct mw_h1req *h1r, size_t age = uatomic_read(&total_bytes_inc); fprintf(fp, "<p>Current age: %zu (live: %zu)", age, age - uatomic_read(&total_bytes_dec)); - FPUTS("<table><tr>", fp); + + if (bt_req_depth) /* need borders to distinguish multi-level traces */ + FPUTS("<table\nborder=1><tr>", fp); + else /* save screen space if only tracing one line */ + FPUTS("<table><tr>", fp); int (*cmp)(const void *, const void *) = NULL; for (size_t i = 0; i < CAA_ARRAY_SIZE(fields); i++) { @@ -603,7 +616,11 @@ static enum mw_qev each_gt(struct mw_h1 *h1, struct mw_h1req *h1r, hsl->bytes, hsl->allocations, hsl->frees, hsl->live, hsl->mean_life, hsl->max_life); FPUTS("<td><a\nhref=\"../at/", fp); - write_uri(fp, hsl->loc_name, hsl->lname_len); + + /* yes, we're writing our memory addresses into the URI */ + write_b64_url(fp, (const void *)&hsl->sl->f, + src_loc_hash_len(hsl->sl)); + FPUTS("\">", fp); write_html(fp, hsl->loc_name, hsl->lname_len); FPUTS("</a></td></tr>", fp); @@ -1025,6 +1042,7 @@ static void *h1d_run(void *x) /* pthread_create cb */ int rc; struct mw_h1 *h1, *nxt; enum mw_qev ev; + locating = 1; /* don't report our own memory use */ for (; uatomic_read(&h1d->alive); ) { if (poll_add(h1d, h1d->lfd, POLLIN)) |