commit 18906bcc2b3035e3483bcff2371e771da0004cae from: Omar Polo date: Wed Sep 13 07:56:13 2023 UTC move the buffering from the fastcgi layer to the template Reduces the indirection in fcgi.c, starts to make the struct template opaque, simplifies the template usage. All with a net negative :-) reads fine to stsp@ (thanks!) commit - 83991185828f6429132ea6dc924774b2c73d7c27 commit + 18906bcc2b3035e3483bcff2371e771da0004cae blob - 8ad3eb7e54a09f151c2bda965bdb7b3dd61b807b blob + e8755e42ab9311cfc4b7fe0d1ab154408818523c --- fcgi.c +++ fcgi.c @@ -37,6 +37,8 @@ #include "galileo.h" #define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define FCGI_MAX_CONTENT_SIZE 65535 struct fcgi_header { unsigned char version; @@ -576,7 +578,8 @@ fcgi_read(struct bufferevent *bev, void *d) break; } - clt->clt_tp = template(clt, clt_tp_puts, clt_tp_putc); + clt->clt_tp = template(clt, clt_write, clt->clt_buf, + sizeof(clt->clt_buf)); if (clt->clt_tp == NULL) { free(clt); log_warn("template"); @@ -686,139 +689,66 @@ fcgi_free(struct fcgi *fcgi) int clt_flush(struct client *clt) +{ + return (template_flush(clt->clt_tp)); +} + +static inline int +dowrite(struct client *clt, const void *data, size_t len) { struct fcgi *fcgi = clt->clt_fcgi; struct bufferevent *bev = fcgi->fcg_bev; struct fcgi_header hdr; - if (clt->clt_buflen == 0) - return (0); - memset(&hdr, 0, sizeof(hdr)); hdr.version = FCGI_VERSION_1; hdr.type = FCGI_STDOUT; hdr.req_id0 = (clt->clt_id & 0xFF); hdr.req_id1 = (clt->clt_id >> 8); - hdr.content_len0 = (clt->clt_buflen & 0xFF); - hdr.content_len1 = (clt->clt_buflen >> 8); + hdr.content_len0 = (len & 0xFF); + hdr.content_len1 = (len >> 8); if (bufferevent_write(bev, &hdr, sizeof(hdr)) == -1 || - bufferevent_write(bev, clt->clt_buf, clt->clt_buflen) == -1) { + bufferevent_write(bev, clt->clt_buf, len) == -1) { fcgi_error(bev, EV_WRITE, fcgi); return (-1); } - clt->clt_buflen = 0; - return (0); } int -clt_write(struct client *clt, const uint8_t *buf, size_t len) +clt_write(void *arg, const void *d, size_t len) { - size_t left, copy; + struct client *clt = arg; + const char *data = d; + size_t avail; while (len > 0) { - left = sizeof(clt->clt_buf) - clt->clt_buflen; - if (left == 0) { - if (clt_flush(clt) == -1) - return (-1); - left = sizeof(clt->clt_buf); - } - - copy = MIN(left, len); - - memcpy(&clt->clt_buf[clt->clt_buflen], buf, copy); - clt->clt_buflen += copy; - buf += copy; - len -= copy; + avail = MIN(len, FCGI_MAX_CONTENT_SIZE); + if (dowrite(clt, data, avail) == -1) + return (-1); + data += avail; + len -= avail; } return (0); } int -clt_putc(struct client *clt, char ch) -{ - return (clt_write(clt, &ch, 1)); -} - -int -clt_puts(struct client *clt, const char *str) -{ - return (clt_write(clt, str, strlen(str))); -} - -int clt_write_bufferevent(struct client *clt, struct bufferevent *bev) { struct evbuffer *src = EVBUFFER_INPUT(bev); - size_t len, left, copy; + size_t len; + int ret; len = EVBUFFER_LENGTH(src); - while (len > 0) { - left = sizeof(clt->clt_buf) - clt->clt_buflen; - if (left == 0) { - if (clt_flush(clt) == -1) - return (-1); - left = sizeof(clt->clt_buf); - } - - copy = bufferevent_read(bev, &clt->clt_buf[clt->clt_buflen], - MIN(left, len)); - clt->clt_buflen += copy; - - len = EVBUFFER_LENGTH(src); - } - - return (0); + ret = clt_write(clt, EVBUFFER_DATA(src), len); + evbuffer_drain(src, len); + return (ret); } int -clt_printf(struct client *clt, const char *fmt, ...) -{ - struct fcgi *fcgi = clt->clt_fcgi; - struct bufferevent *bev = fcgi->fcg_bev; - char *str; - va_list ap; - int r; - - va_start(ap, fmt); - r = vasprintf(&str, fmt, ap); - va_end(ap); - if (r == -1) { - fcgi_error(bev, EV_WRITE, fcgi); - return (-1); - } - - r = clt_write(clt, str, r); - free(str); - return (r); -} - -int -clt_tp_puts(struct template *tp, const char *str) -{ - struct client *clt = tp->tp_arg; - - if (clt_puts(clt, str) == -1) - return (-1); - - return (0); -} - -int -clt_tp_putc(struct template *tp, int c) -{ - struct client *clt = tp->tp_arg; - - if (clt_putc(clt, c) == -1) - return (-1); - - return (0); -} - -int fcgi_cmp(struct fcgi *a, struct fcgi *b) { return ((int)a->fcg_id - b->fcg_id); blob - 05a8126ae966aec99082f671e6dc52680c168fd9 blob + 7c07219997055de3dd12bd37dfdead4e69fa894c --- galileo.h +++ galileo.h @@ -103,7 +103,6 @@ struct client { int clt_translate; char clt_buf[1024]; - size_t clt_buflen; SPLAY_ENTRY(client) clt_nodes; }; @@ -185,16 +184,9 @@ void fcgi_read(struct bufferevent *, void *); void fcgi_write(struct bufferevent *, void *); void fcgi_error(struct bufferevent *, short error, void *); void fcgi_free(struct fcgi *); -int clt_putc(struct client *, char); -int clt_puts(struct client *, const char *); int clt_write_bufferevent(struct client *, struct bufferevent *); int clt_flush(struct client *); -int clt_write(struct client *, const uint8_t *, size_t); -int clt_printf(struct client *, const char *, ...) - __attribute__((__format__(printf, 2, 3))) - __attribute__((__nonnull__(2))); -int clt_tp_puts(struct template *, const char *); -int clt_tp_putc(struct template *, int); +int clt_write(void *, const void *, size_t); int fcgi_cmp(struct fcgi *, struct fcgi *); int fcgi_client_cmp(struct client *, struct client *); blob - e68c29ebb94b7838ee92572d741ba5903e4c35fe blob + 7b554d2017bcdfad1c15b6473a1b93f322ad9e4d --- proxy.c +++ proxy.c @@ -256,6 +256,7 @@ match_image_heur(const char *url) static int gemtext_translate_line(struct client *clt, char *line) { + struct template *tp = clt->clt_tp; char buf[1025]; char *url; @@ -268,32 +269,32 @@ gemtext_translate_line(struct client *clt, char *line) if (tp_htmlescape(clt->clt_tp, line) == -1) return (-1); - return (clt_putc(clt, '\n')); + return (tp_write(tp, "\n", 1)); } /* bullet */ if (!strncmp(line, "* ", 2)) { if (clt->clt_translate & TR_NAV) { - if (clt_puts(clt, "") == -1) + if (tp_writes(tp, "") == -1) return (-1); clt->clt_translate &= ~TR_NAV; } if (!(clt->clt_translate & TR_LIST)) { - if (clt_puts(clt, "") == -1) return (-1); clt->clt_translate &= ~TR_LIST; } @@ -323,37 +324,37 @@ gemtext_translate_line(struct client *clt, char *line) if (!(clt->clt_pc->flags & PROXY_NO_IMGPRV) && match_image_heur(url)) { if (clt->clt_translate & TR_NAV) { - if (clt_puts(clt, "") == -1) + if (tp_writes(tp, "") == -1) return (-1); clt->clt_translate &= ~TR_NAV; } - if (tp_figure(clt->clt_tp, url, label) == -1) + if (tp_figure(tp, url, label) == -1) return (-1); return (0); } if (!(clt->clt_translate & TR_NAV)) { - if (clt_puts(clt, "") == -1) return (-1); clt->clt_translate &= ~TR_NAV; } @@ -364,37 +365,37 @@ gemtext_translate_line(struct client *clt, char *line) line += strspn(line, " \t"); clt->clt_translate |= TR_PRE; - return (tp_pre_open(clt->clt_tp, line)); + return (tp_pre_open(tp, line)); } /* citation block */ if (*line == '>') { - if (clt_puts(clt, "
") == -1 || + if (tp_writes(tp, "
") == -1 || tp_htmlescape(clt->clt_tp, line + 1) == -1 || - clt_puts(clt, "
") == -1) + tp_writes(tp, "
") == -1) return (-1); return (0); } /* headings */ if (!strncmp(line, "###", 3)) { - if (clt_puts(clt, "

") == -1 || + if (tp_writes(tp, "

") == -1 || tp_htmlescape(clt->clt_tp, line + 3) == -1 || - clt_puts(clt, "

") == -1) + tp_writes(tp, "") == -1) return (-1); return (0); } if (!strncmp(line, "##", 2)) { - if (clt_puts(clt, "

") == -1 || + if (tp_writes(tp, "

") == -1 || tp_htmlescape(clt->clt_tp, line + 2) == -1 || - clt_puts(clt, "

") == -1) + tp_writes(tp, "") == -1) return (-1); return (0); } if (!strncmp(line, "#", 1)) { - if (clt_puts(clt, "

") == -1 || + if (tp_writes(tp, "

") == -1 || tp_htmlescape(clt->clt_tp, line + 1) == -1 || - clt_puts(clt, "

") == -1) + tp_writes(tp, "") == -1) return (-1); return (0); } @@ -404,9 +405,9 @@ gemtext_translate_line(struct client *clt, char *line) return (0); /* paragraph */ - if (clt_puts(clt, "

") == -1 || + if (tp_writes(tp, "

") == -1 || tp_htmlescape(clt->clt_tp, line) == -1 || - clt_puts(clt, "

") == -1) + tp_writes(tp, "

") == -1) return (-1); return (0); @@ -721,23 +722,24 @@ parse_mime(struct client *clt, char *mime, char *lang, int proxy_start_reply(struct client *clt, int status, const char *ctype) { + struct template *tp = clt->clt_tp; const char *csp; csp = "Content-Security-Policy: default-src 'self'; " "script-src 'none'; object-src 'none';\r\n"; if (status != 200 && - clt_printf(clt, "Status: %d\r\n", status) == -1) + tp_writef(tp, "Status: %d\r\n", status) == -1) return (-1); - if (clt_puts(clt, csp) == -1) + if (tp_writes(tp, csp) == -1) return (-1); if (status == 302) { /* use "ctype" as redirect target */ - if (clt_printf(clt, "Location: %s\r\n", ctype) == -1) + if (tp_writef(tp, "Location: %s\r\n", ctype) == -1) return (-1); - if (clt_puts(clt, "\r\n") == -1) + if (tp_writes(tp, "\r\n") == -1) return (-1); return (0); } @@ -745,12 +747,12 @@ proxy_start_reply(struct client *clt, int status, cons if (ctype != NULL) { if (!strcmp(ctype, "text/html")) ctype = "text/html;charset=utf-8"; - if (clt_printf(clt, "Content-Type: %s\r\n", ctype) + if (tp_writef(tp, "Content-Type: %s\r\n", ctype) == -1) return (-1); } - if (clt_puts(clt, "\r\n") == -1) + if (tp_writes(tp, "\r\n") == -1) return (-1); return (0); @@ -837,7 +839,7 @@ proxy_read(struct bufferevent *bev, void *d) else ctype = mime; - if (clt_printf(clt, "Content-Type: %s\r\n\r\n", ctype) == -1) + if (tp_writef(clt->clt_tp, "Content-Type: %s\r\n\r\n", ctype) == -1) goto err; clt->clt_headersdone = 1; @@ -868,6 +870,7 @@ void proxy_error(struct bufferevent *bev, short err, void *d) { struct client *clt = d; + struct template *tp = clt->clt_tp; int status = !(err & EVBUFFER_EOF); log_debug("proxy error, shutting down the connection (err: %x)", @@ -886,13 +889,13 @@ proxy_error(struct bufferevent *bev, short err, void * } if (clt->clt_translate & TR_LIST) { - if (clt_puts(clt, "") == -1) + if (tp_writes(tp, "") == -1) return; clt->clt_translate &= ~TR_LIST; } if (clt->clt_translate & TR_NAV) { - if (clt_puts(clt, "") == -1) + if (tp_writes(tp, "") == -1) return; clt->clt_translate &= ~TR_NAV; } blob - c97478128fa19c9cddcf687a802db929cfa6bd36 blob + 59cf6888097e2e08fde77614c4ea7f9517e3f4ac --- template/parse.y +++ template/parse.y @@ -139,9 +139,10 @@ verbatims : /* empty */ raw : nstring { dbg(); - fprintf(fp, "if ((tp_ret = tp->tp_puts(tp, "); + fprintf(fp, "if ((tp_ret = tp_write(tp, "); printq($1); - fputs(")) == -1) goto err;\n", fp); + fprintf(fp, ", %zu)) == -1) goto err;\n", + strlen($1)); free($1); } @@ -189,7 +190,7 @@ special : '{' RENDER string '}' { | '{' string '|' UNSAFE '}' { dbg(); fprintf(fp, - "if ((tp_ret = tp->tp_puts(tp, %s)) == -1)\n", + "if ((tp_ret = tp_writes(tp, %s)) == -1)\n", $2); fputs("goto err;\n", fp); free($2); @@ -205,7 +206,7 @@ special : '{' RENDER string '}' { | '{' string '}' { dbg(); fprintf(fp, - "if ((tp_ret = tp->tp_escape(tp, %s)) == -1)\n", + "if ((tp_ret = tp_htmlescape(tp, %s)) == -1)\n", $2); fputs("goto err;\n", fp); free($2); @@ -218,7 +219,7 @@ printf : '{' PRINTF { } printfargs '}' { fputs(") == -1)\n", fp); fputs("goto err;\n", fp); - fputs("if ((tp_ret = tp->tp_escape(tp, tp->tp_tmp)) " + fputs("if ((tp_ret = tp_htmlescape(tp, tp->tp_tmp)) " "== -1)\n", fp); fputs("goto err;\n", fp); fputs("free(tp->tp_tmp);\n", fp); blob - 0d5556832752616b4191a8cf21835e45f65b16b4 blob + a26f893929de81045bf85ad76631aa136e7d86b3 --- template/regress/runbase.c +++ template/regress/runbase.c @@ -21,42 +21,36 @@ #include "tmpl.h" int base(struct template *, const char *title); +int my_write(void *, const void *, size_t); int -my_putc(struct template *tp, int c) +my_write(void *arg, const void *s, size_t len) { - FILE *fp = tp->tp_arg; + FILE *fp = arg; - if (putc(c, fp) < 0) + if (fwrite(s, 1, len, fp) < 0) return (-1); return (0); } int -my_puts(struct template *tp, const char *s) -{ - FILE *fp = tp->tp_arg; - - if (fputs(s, fp) < 0) - return (-1); - - return (0); -} - -int main(int argc, char **argv) { - struct template *tp; + struct template *tp; + char buf[3]; + /* use a ridiculously small buffer in regress */ - if ((tp = template(stdout, my_puts, my_putc)) == NULL) + if ((tp = template(stdout, my_write, buf, sizeof(buf))) == NULL) err(1, "template"); - if (base(tp, " *hello* ") == -1) + if (base(tp, " *hello* ") == -1 || + template_flush(tp) == -1) return (1); puts(""); - if (base(tp, "") == -1) + if (base(tp, "") == -1 || + template_flush(tp) == -1) return (1); puts(""); blob - 70491763b5ea06841ec7b67897202e9bfb3c3223 blob + 648bcc07fa18e09307682160f77408c3d644530c --- template/regress/runlist.c +++ template/regress/runlist.c @@ -22,38 +22,30 @@ #include "lists.h" int base(struct template *, struct tailhead *); +int my_write(void *, const void *, size_t); int -my_putc(struct template *tp, int c) +my_write(void *arg, const void *s, size_t len) { - FILE *fp = tp->tp_arg; + FILE *fp = arg; - if (putc(c, fp) < 0) + if (fwrite(s, 1, len, fp) < 0) return (-1); return (0); } int -my_puts(struct template *tp, const char *s) -{ - FILE *fp = tp->tp_arg; - - if (fputs(s, fp) < 0) - return (-1); - - return (0); -} - -int main(int argc, char **argv) { struct template *tp; struct tailhead head; struct entry *np; int i; + char buf[3]; + /* use a ridiculously small buffer in regress */ - if ((tp = template(stdout, my_puts, my_putc)) == NULL) + if ((tp = template(stdout, my_write, buf, sizeof(buf))) == NULL) err(1, "template"); TAILQ_INIT(&head); @@ -65,7 +57,8 @@ main(int argc, char **argv) TAILQ_INSERT_TAIL(&head, np, entries); } - if (base(tp, &head) == -1) + if (base(tp, &head) == -1 || + template_flush(tp) == -1) return (1); puts(""); @@ -75,7 +68,8 @@ main(int argc, char **argv) free(np); } - if (base(tp, &head) == -1) + if (base(tp, &head) == -1 || + template_flush(tp) == -1) return (1); puts(""); blob - 18ee428516dc3b90ef925c5ac135e90278c0d5f9 blob + 5f1093f5488dc59cedb4551421207df0fb7e025d --- template/tmpl.c +++ template/tmpl.c @@ -15,12 +15,62 @@ */ #include +#include #include #include +#include #include "tmpl.h" int +tp_write(struct template *tp, const char *str, size_t len) +{ + size_t avail; + + while (len > 0) { + avail = tp->tp_cap - tp->tp_len; + if (avail == 0) { + if (template_flush(tp) == -1) + return (-1); + avail = tp->tp_cap; + } + + if (len < avail) + avail = len; + + memcpy(tp->tp_buf + tp->tp_len, str, avail); + tp->tp_len += avail; + str += avail; + len -= avail; + } + + return (0); +} + +int +tp_writes(struct template *tp, const char *str) +{ + return (tp_write(tp, str, strlen(str))); +} + +int +tp_writef(struct template *tp, const char *fmt, ...) +{ + va_list ap; + char *str; + int r; + + va_start(ap, fmt); + r = vasprintf(&str, fmt, ap); + va_end(ap); + if (r == -1) + return (-1); + r = tp_write(tp, str, r); + free(str); + return (r); +} + +int tp_urlescape(struct template *tp, const char *str) { int r; @@ -36,10 +86,10 @@ tp_urlescape(struct template *tp, const char *str) r = snprintf(tmp, sizeof(tmp), "%%%2X", *str); if (r < 0 || (size_t)r >= sizeof(tmp)) return (0); - if (tp->tp_puts(tp, tmp) == -1) + if (tp_write(tp, tmp, r) == -1) return (-1); } else { - if (tp->tp_putc(tp, *str) == -1) + if (tp_write(tp, str, 1) == -1) return (-1); } } @@ -58,22 +108,22 @@ tp_htmlescape(struct template *tp, const char *str) for (; *str; ++str) { switch (*str) { case '<': - r = tp->tp_puts(tp, "<"); + r = tp_write(tp, "<", 4); break; case '>': - r = tp->tp_puts(tp, ">"); + r = tp_write(tp, ">", 4); break; case '&': - r = tp->tp_puts(tp, "&"); + r = tp_write(tp, "&", 5); break; case '"': - r = tp->tp_puts(tp, """); + r = tp_write(tp, """, 6); break; case '\'': - r = tp->tp_puts(tp, "'"); + r = tp_write(tp, "'", 6); break; default: - r = tp->tp_putc(tp, *str); + r = tp_write(tp, str, 1); break; } @@ -85,7 +135,7 @@ tp_htmlescape(struct template *tp, const char *str) } struct template * -template(void *arg, tmpl_puts putsfn, tmpl_putc putcfn) +template(void *arg, tmpl_write writefn, char *buf, size_t siz) { struct template *tp; @@ -93,13 +143,25 @@ template(void *arg, tmpl_puts putsfn, tmpl_putc putcfn return (NULL); tp->tp_arg = arg; - tp->tp_escape = tp_htmlescape; - tp->tp_puts = putsfn; - tp->tp_putc = putcfn; + tp->tp_write = writefn; + tp->tp_buf = buf; + tp->tp_cap = siz; return (tp); } +int +template_flush(struct template *tp) +{ + if (tp->tp_len == 0) + return (0); + + if (tp->tp_write(tp->tp_arg, tp->tp_buf, tp->tp_len) == -1) + return (-1); + tp->tp_len = 0; + return (0); +} + void template_free(struct template *tp) { blob - 4c8de903c9b7957de3c6bc1ed2058fa9a5db553b blob + df3b74c2696e16f2a591fb656220ac7957c59a56 --- template/tmpl.h +++ template/tmpl.h @@ -19,21 +19,26 @@ struct template; -typedef int (*tmpl_puts)(struct template *, const char *); -typedef int (*tmpl_putc)(struct template *, int); +typedef int (*tmpl_write)(void *, const void *, size_t); struct template { void *tp_arg; char *tp_tmp; - tmpl_puts tp_escape; - tmpl_puts tp_puts; - tmpl_putc tp_putc; + tmpl_write tp_write; + char *tp_buf; + size_t tp_len; + size_t tp_cap; }; -int tp_urlescape(struct template *, const char *); -int tp_htmlescape(struct template *, const char *); +int tp_write(struct template *, const char *, size_t); +int tp_writes(struct template *, const char *); +int tp_writef(struct template *, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); +int tp_urlescape(struct template *, const char *); +int tp_htmlescape(struct template *, const char *); -struct template *template(void *, tmpl_puts, tmpl_putc); +struct template *template(void *, tmpl_write, char *, size_t); +int template_flush(struct template *); void template_free(struct template *); #endif