commit ed619ca07e51b9c984c8404ca2b1153efdb14d1e from: Omar Polo date: Wed Dec 14 18:05:43 2022 UTC gotwebd: start using the template system ok tracey@ commit - 2c02675e51b8f7413665e81e1e2f3bf77ee9acb7 commit + ed619ca07e51b9c984c8404ca2b1153efdb14d1e blob - 8744ffb84ade1da058f9e9837fdbbd91cd5130fc blob + 1f2783a446360c7e3379bbca5be3bea0ee1e76c5 --- gotwebd/Makefile +++ gotwebd/Makefile @@ -1,4 +1,5 @@ .PATH:${.CURDIR}/../lib +.PATH:${.CURDIR}/../template SUBDIR = libexec @@ -7,7 +8,7 @@ SUBDIR = libexec PROG = gotwebd SRCS = config.c sockets.c log.c gotwebd.c parse.y proc.c \ - fcgi.c gotweb.c got_operations.c + fcgi.c gotweb.c got_operations.c tmpl.c pages.c SRCS += blame.c commit_graph.c delta.c diff.c \ diffreg.c error.c fileindex.c object.c object_cache.c \ object_idset.c object_parse.c opentemp.c path.c pack.c \ @@ -21,9 +22,20 @@ SRCS += blame.c commit_graph.c delta.c diff.c \ object_open_privsep.c read_gitconfig_privsep.c \ read_gotconfig_privsep.c pollfd.c reference_parse.c +.if exists(${.CURDIR}/../template/obj/template) +TEMPLATE = ${.CURDIR}/../template/obj/template +.else +TEMPLATE = ${.CURDIR}/../template/template +.endif + +.SUFFIXES: .tmpl +.tmpl.c: + ${TEMPLATE} -o $@ $< + MAN = ${PROG}.conf.5 ${PROG}.8 CPPFLAGS += -I${.CURDIR}/../include -I${.CURDIR}/../lib -I${.CURDIR} +CPPFLAGS += -I${.CURDIR}/../template LDADD += -lz -levent -lutil -lm YFLAGS = DPADD = ${LIBEVENT} ${LIBUTIL} blob - 04e9e72ece31adeacc0aef6f6fb7cffbaace078a blob + b4f85fc2121de39b9a1c7ff2f9fcab75f5b7da42 --- gotwebd/fcgi.c +++ gotwebd/fcgi.c @@ -36,6 +36,7 @@ #include "proc.h" #include "gotwebd.h" +#include "tmpl.h" size_t fcgi_parse_record(uint8_t *, size_t, struct request *); void fcgi_parse_begin_request(uint8_t *, uint16_t, struct request *, @@ -288,6 +289,21 @@ fcgi_timeout(int fd, short events, void *arg) } int +fcgi_puts(struct template *tp, const char *str) +{ + if (str == NULL) + return 0; + return fcgi_gen_binary_response(tp->tp_arg, str, strlen(str)); +} + +int +fcgi_putc(struct template *tp, int ch) +{ + uint8_t c = ch; + return fcgi_gen_binary_response(tp->tp_arg, &c, 1); +} + +int fcgi_vprintf(struct request *c, const char *fmt, va_list ap) { char *str; @@ -483,6 +499,7 @@ fcgi_cleanup_request(struct request *c) event_del(&c->ev); close(c->fd); + template_free(c->tp); gotweb_free_transport(c->t); free(c); } blob - fc0c94f6c50f1675561ef2a30f20c748df22416c blob + 0ce90275bab1028c73efcf66d2d59a727f7ca7c7 --- gotwebd/gotweb.c +++ gotwebd/gotweb.c @@ -51,11 +51,6 @@ #include "proc.h" #include "gotwebd.h" -enum gotweb_ref_tm { - TM_DIFF, - TM_LONG, -}; - static const struct querystring_keys querystring_keys[] = { { "action", ACTION }, { "commit", COMMIT }, @@ -86,8 +81,6 @@ static const struct got_error *gotweb_parse_querystrin char *); static const struct got_error *gotweb_assign_querystring(struct querystring **, char *, char *); -static const struct got_error *gotweb_render_header(struct request *); -static const struct got_error *gotweb_render_footer(struct request *); static const struct got_error *gotweb_render_index(struct request *); static const struct got_error *gotweb_init_repo_dir(struct repo_dir **, const char *); @@ -97,9 +90,7 @@ static const struct got_error *gotweb_get_repo_descrip struct server *, const char *, int); static const struct got_error *gotweb_get_clone_url(char **, struct server *, const char *, int); -static const struct got_error *gotweb_render_navs(struct request *); static const struct got_error *gotweb_render_blame(struct request *); -static const struct got_error *gotweb_render_briefs(struct request *); static const struct got_error *gotweb_render_commits(struct request *); static const struct got_error *gotweb_render_diff(struct request *); static const struct got_error *gotweb_render_summary(struct request *); @@ -108,6 +99,8 @@ static const struct got_error *gotweb_render_tags(stru static const struct got_error *gotweb_render_tree(struct request *); static const struct got_error *gotweb_render_branches(struct request *); +const struct got_error *gotweb_render_navs(struct request *); + static void gotweb_free_querystring(struct querystring *); static void gotweb_free_repo_dir(struct repo_dir *); @@ -195,11 +188,8 @@ render: } html = 1; - error = gotweb_render_header(c); - if (error) { - log_warnx("%s: %s", __func__, error->msg); + if (gotweb_render_header(c->tp) == -1) goto err; - } if (error2) { error = error2; @@ -215,11 +205,8 @@ render: } break; case BRIEFS: - error = gotweb_render_briefs(c); - if (error) { - log_warnx("%s: %s", __func__, error->msg); + if (gotweb_render_briefs(c->tp) == -1) goto err; - } break; case COMMITS: error = gotweb_render_commits(c); @@ -296,7 +283,7 @@ err: return; done: if (html && srv != NULL) - gotweb_render_footer(c); + gotweb_render_footer(c->tp); } struct server * @@ -691,146 +678,8 @@ gotweb_render_content_type_file(struct request *c, con type, file); return NULL; } - -static const struct got_error * -gotweb_render_header(struct request *c) -{ - const struct got_error *err = NULL; - struct server *srv = c->srv; - struct querystring *qs = c->t->qs; - int r; - - r = fcgi_printf(c, "\n" - "\n" - "\n" - "%s\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "\n" - "
\n" - "\n" /* #header */ - "
\n" - "\n" /* #site_path */ - "
\n" /* #site_link */ - "
\n"); - -done: - return NULL; -} - -static const struct got_error * -gotweb_render_footer(struct request *c) -{ - const struct got_error *error = NULL; - struct server *srv = c->srv; - const char *siteowner = " "; - char *escaped_owner = NULL; - - if (srv->show_site_owner) { - error = gotweb_escape_html(&escaped_owner, srv->site_owner); - if (error) - return error; - siteowner = escaped_owner; - } - - fcgi_printf(c, "
\n" - "
%s
\n" - "
\n" /* #site_owner_wrapper */ - "
\n" /* #content */ - "
\n" /* #gw_body */ - "\n\n", siteowner); - - free(escaped_owner); - return NULL; -} - -static const struct got_error * +const struct got_error * gotweb_render_navs(struct request *c) { const struct got_error *error = NULL; @@ -996,7 +845,7 @@ gotweb_render_index(struct request *c) struct dirent **sd_dent = NULL; unsigned int d_cnt, d_i, d_disp = 0; unsigned int d_skipped = 0; - int r, type; + int type; d = opendir(srv->repos_path); if (d == NULL) { @@ -1011,26 +860,9 @@ gotweb_render_index(struct request *c) goto done; } - r = fcgi_printf(c, "
\n" - "
Project
\n"); - if (r == -1) + if (gotweb_render_repo_table_hdr(c->tp) == -1) goto done; - if (srv->show_repo_description) - if (fcgi_printf(c, "
" - "Description
\n") == -1) - goto done; - if (srv->show_repo_owner) - if (fcgi_printf(c, "
" - "Owner
\n") == -1) - goto done; - if (srv->show_repo_age) - if (fcgi_printf(c, "
" - "Last Change
\n") == -1) - goto done; - if (fcgi_printf(c, "
\n") == -1) /* #index_header */ - goto done; - for (d_i = 0; d_i < d_cnt; d_i++) { if (srv->max_repos > 0 && t->prev_disp == srv->max_repos) break; @@ -1074,112 +906,9 @@ gotweb_render_index(struct request *c) d_disp++; t->prev_disp++; - if (fcgi_printf(c, "
\n" - "
") == -1) - goto done; - - r = gotweb_link(c, &(struct gotweb_url){ - .action = SUMMARY, - .index_page = -1, - .page = -1, - .path = repo_dir->name, - }, "%s", repo_dir->name); - if (r == -1) - goto done; - - if (fcgi_printf(c, "
") == -1) /* .index_project */ - goto done; - - if (srv->show_repo_description) { - r = fcgi_printf(c, - "
\n" - "%s
\n", repo_dir->description); - if (r == -1) - goto done; - } - - if (srv->show_repo_owner) { - r = fcgi_printf(c, "
" - "%s
\n", repo_dir->owner); - if (r == -1) - goto done; - } - - if (srv->show_repo_age) { - r = fcgi_printf(c, "
" - "%s
\n", repo_dir->age); - if (r == -1) - goto done; - } - - if (fcgi_printf(c, "\n" /* .navs_wrapper */ - "
\n"); /* .index_wrapper */ - if (r == -1) - goto done; - gotweb_free_repo_dir(repo_dir); repo_dir = NULL; t->next_disp++; @@ -1264,143 +993,6 @@ done: } static const struct got_error * -gotweb_render_briefs(struct request *c) -{ - const struct got_error *error = NULL; - struct repo_commit *rc = NULL; - struct server *srv = c->srv; - struct transport *t = c->t; - struct querystring *qs = t->qs; - struct repo_dir *repo_dir = t->repo_dir; - char *smallerthan, *newline; - char *age = NULL, *author = NULL, *msg = NULL; - int r; - - r = fcgi_printf(c, "
\n" - "
Commit Briefs
\n" - "
\n" /* #briefs_title_wrapper */ - "
\n"); - if (r == -1) - goto done; - - if (qs->action == SUMMARY) { - qs->action = BRIEFS; - error = got_get_repo_commits(c, D_MAXSLCOMMDISP); - } else - error = got_get_repo_commits(c, srv->max_commits_display); - if (error) - goto done; - - TAILQ_FOREACH(rc, &t->repo_commits, entry) { - error = gotweb_get_time_str(&age, rc->committer_time, TM_DIFF); - if (error) - goto done; - - smallerthan = strchr(rc->author, '<'); - if (smallerthan) - *smallerthan = '\0'; - - newline = strchr(rc->commit_msg, '\n'); - if (newline) - *newline = '\0'; - - error = gotweb_escape_html(&author, rc->author); - if (error) - goto done; - error = gotweb_escape_html(&msg, rc->commit_msg); - if (error) - goto done; - - r = fcgi_printf(c, "
%s
\n" - "
%s
\n" - "
", - age, author); - if (r == -1) - goto done; - - r = gotweb_link(c, &(struct gotweb_url){ - .action = DIFF, - .index_page = -1, - .page = -1, - .path = repo_dir->name, - .commit = rc->commit_id, - .headref = qs->headref, - }, "%s", msg); - if (r == -1) - goto done; - - if (rc->refs_str) { - char *refs; - - error = gotweb_escape_html(&refs, rc->refs_str); - if (error) - goto done; - r = fcgi_printf(c, - " (%s)", refs); - free(refs); - if (r == -1) - goto done; - } - if (fcgi_printf(c, "
\n") == -1) /* .briefs_log */ - goto done; - - r = fcgi_printf(c, "\n" /* .navs_wrapper */ - "
\n") == -1) - goto done; - - free(age); - age = NULL; - free(author); - author = NULL; - free(msg); - msg = NULL; - } - - if (t->next_id || t->prev_id) { - error = gotweb_render_navs(c); - if (error) - goto done; - } - fcgi_printf(c, "
\n"); /* #briefs_content */ -done: - free(age); - free(author); - free(msg); - return error; -} - -static const struct got_error * gotweb_render_commits(struct request *c) { const struct got_error *error = NULL; @@ -1811,11 +1403,8 @@ gotweb_render_summary(struct request *c) if (r == -1) goto done; - error = gotweb_render_briefs(c); - if (error) { - log_warnx("%s: %s", __func__, error->msg); + if (gotweb_render_briefs(c->tp) == -1) goto done; - } error = gotweb_render_tags(c); if (error) { @@ -2177,8 +1766,8 @@ gotweb_urlencode(const char *str) return escaped; } -static inline const char * -action_name(int action) +const char * +gotweb_action_name(int action) { switch (action) { case BLAME: @@ -2208,14 +1797,14 @@ action_name(int action) } } -static int -gotweb_print_url(struct request *c, struct gotweb_url *url) +int +gotweb_render_url(struct request *c, struct gotweb_url *url) { const char *sep = "?", *action; char *tmp; int r; - action = action_name(url->action); + action = gotweb_action_name(url->action); if (action != NULL) { if (fcgi_printf(c, "?action=%s", action) == -1) return -1; @@ -2309,7 +1898,7 @@ gotweb_link(struct request *c, struct gotweb_url *url, if (fcgi_printf(c, "") == -1) blob - 14426b3f4ad9787e7876dc233211e8fb8875cab6 blob + 64fce7c6d8ee3f57305034f0c0434cff991a82bd --- gotwebd/gotwebd.h +++ gotwebd/gotwebd.h @@ -202,10 +202,12 @@ enum socket_priv_fds { PRIV_FDS__MAX, }; +struct template; struct request { struct socket *sock; struct server *srv; struct transport *t; + struct template *tp; struct event ev; struct event tmo; @@ -415,6 +417,11 @@ enum query_actions { ACTIONS__MAX, }; +enum gotweb_ref_tm { + TM_DIFF, + TM_LONG, +}; + extern struct gotwebd *gotwebd_env; /* sockets.c */ @@ -432,6 +439,8 @@ const struct got_error const struct got_error *gotweb_get_time_str(char **, time_t, int); const struct got_error *gotweb_init_transport(struct transport **); const struct got_error *gotweb_escape_html(char **, const char *); +const char *gotweb_action_name(int); +int gotweb_render_url(struct request *, struct gotweb_url *); int gotweb_link(struct request *, struct gotweb_url *, const char *, ...) __attribute__((__format__(printf, 3, 4))) __attribute__((__nonnull__(3))); @@ -440,6 +449,13 @@ void gotweb_free_repo_tag(struct repo_tag *); void gotweb_process_request(struct request *); void gotweb_free_transport(struct transport *); +/* pages.tmpl */ +int gotweb_render_header(struct template *); +int gotweb_render_footer(struct template *); +int gotweb_render_repo_table_hdr(struct template *); +int gotweb_render_repo_fragment(struct template *, struct repo_dir *); +int gotweb_render_briefs(struct template *); + /* parse.y */ int parse_config(const char *, struct gotwebd *); int cmdline_symset(char *); @@ -450,6 +466,8 @@ void fcgi_timeout(int, short, void *); void fcgi_cleanup_request(struct request *); void fcgi_create_end_record(struct request *); void dump_fcgi_record(const char *, struct fcgi_record_header *); +int fcgi_puts(struct template *, const char *); +int fcgi_putc(struct template *, int); int fcgi_vprintf(struct request *, const char *, va_list); int fcgi_printf(struct request *, const char *, ...) __attribute__((__format__(printf, 2, 3))) blob - /dev/null blob + 0d49898e174e9bfad77b158729eb04ab949bd736 (mode 644) --- /dev/null +++ gotwebd/pages.tmpl @@ -0,0 +1,302 @@ +{! +/* + * Copyright (c) 2022 Omar Polo + * Copyright (c) 2016, 2019, 2020-2022 Tracey Emery + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "proc.h" + +#include "gotwebd.h" +#include "tmpl.h" + +const struct got_error *gotweb_render_navs(struct request *); + +static int +gotweb_render_age(struct template *tp, time_t time, int ref_tm) +{ + const struct got_error *err; + char *age; + int r; + + err = gotweb_get_time_str(&age, time, ref_tm); + if (err) + return 0; + r = tp->tp_puts(tp, age); + free(age); + return r; +} + +!} + +{{ define gotweb_render_header(struct template *tp) }} +{! + struct request *c = tp->tp_arg; + struct server *srv = c->srv; + struct querystring *qs = c->t->qs; + struct gotweb_url u_path; + const char *prfx = c->script_name; + const char *css = srv->custom_css; + + memset(&u_path, 0, sizeof(u_path)); + u_path.index_page = -1; + u_path.page = -1; + u_path.action = SUMMARY; +!} + + + + + {{ srv->site_name }} + + + + + + + + + + + +
+ +
+ +
+
+{{ end }} + +{{ define gotweb_render_footer(struct template *tp) }} +{! + struct request *c = tp->tp_arg; + struct server *srv = c->srv; +!} +
+
+ {{ if srv->show_site_owner }} + {{ srv->site_owner }} + {{ end }} +
+
+
+
+ + +{{ end }} + +{{ define gotweb_render_repo_table_hdr(struct template *tp) }} +{! + struct request *c = tp->tp_arg; + struct server *srv = c->srv; +!} +
+
+ Project +
+ {{ if srv->show_repo_description }} +
+ Description +
+ {{ end }} + {{ if srv->show_repo_owner }} +
+ Owner +
+ {{ end }} + {{ if srv->show_repo_age }} +
+ Last Change +
+ {{ end }} +
+{{ end }} + +{{ define gotweb_render_repo_fragment(struct template *tp, struct repo_dir *repo_dir) }} +{! + struct request *c = tp->tp_arg; + struct server *srv = c->srv; + struct gotweb_url summary = { + .action = SUMMARY, + .index_page = -1, + .page = -1, + .path = repo_dir->name, + }, briefs = { + .action = BRIEFS, + .index_page = -1, + .page = -1, + .path = repo_dir->name, + }, commits = { + .action = COMMITS, + .index_page = -1, + .page = -1, + .path = repo_dir->name, + }, tags = { + .action = TAGS, + .index_page = -1, + .page = -1, + .path = repo_dir->name, + }, tree = { + .action = TREE, + .index_page = -1, + .page = -1, + .path = repo_dir->name, + }; +!} +
+ + {{ if srv->show_repo_description }} +
+ {{ repo_dir->description }} +
+ {{ end }} + {{ if srv->show_repo_owner }} +
+ {{ repo_dir->owner }} +
+ {{ end }} + {{ if srv->show_repo_age }} +
+ {{ repo_dir->age }} +
+ {{ end }} + +
+{{ end }} + +{{ define gotweb_render_briefs(struct template *tp) }} +{! + const struct got_error *error; + struct request *c = tp->tp_arg; + struct server *srv = c->srv; + struct transport *t = c->t; + struct querystring *qs = c->t->qs; + struct repo_commit *rc; + struct repo_dir *repo_dir = t->repo_dir; + struct gotweb_url diff_url, tree_url; + char *tmp; + + diff_url = (struct gotweb_url){ + .action = DIFF, + .index_page = -1, + .page = -1, + .path = repo_dir->name, + .headref = qs->headref, + }; + tree_url = (struct gotweb_url){ + .action = TREE, + .index_page = -1, + .page = -1, + .path = repo_dir->name, + .headref = qs->headref, + }; + + if (qs->action == SUMMARY) { + qs->action = BRIEFS; + error = got_get_repo_commits(c, D_MAXSLCOMMDISP); + } else + error = got_get_repo_commits(c, srv->max_commits_display); + if (error) + return -1; +!} +
+
Commit Briefs
+
+
+ {{ tailq-foreach rc &t->repo_commits entry }} + {! + diff_url.commit = rc->commit_id; + tree_url.commit = rc->commit_id; + + tmp = strchr(rc->author, '<'); + if (tmp) + *tmp = '\0'; + + tmp = strchr(rc->commit_msg, '\n'); + if (tmp) + *tmp = '\0'; + !} +
+ {{ render gotweb_render_age(tp, rc->committer_time, TM_DIFF) }} +
+
+ {{ rc->author }} +
+
+ + {{ rc->commit_msg }} + + {{ if rc->refs_str }} + {{ " " }} ({{ rc->refs_str }}) + {{ end }} + +
+ +
+ {{ end }} + {{ if t->next_id || t->prev_id }} + {! gotweb_render_navs(c); !} + {{ end }} +
+{{ end }} blob - c0691c5575dca8c931af0e8e30d9e086b5a5bccc blob + cfba5dfb0e7368b0b37738d2eb71b53d437db169 --- gotwebd/sockets.c +++ gotwebd/sockets.c @@ -55,6 +55,7 @@ #include "proc.h" #include "gotwebd.h" +#include "tmpl.h" #define SOCKS_BACKLOG 5 #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) @@ -613,9 +614,18 @@ sockets_socket_accept(int fd, short event, void *arg) c = calloc(1, sizeof(struct request)); if (c == NULL) { + log_warn("%s", __func__); + close(s); + cgi_inflight--; + return; + } + + c->tp = template(c, fcgi_puts, fcgi_putc); + if (c->tp == NULL) { log_warn("%s", __func__); close(s); cgi_inflight--; + free(c); return; }