"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Mark Jamsek <mark@jamsek.com>
Subject:
Re: gotwebd: introducing fcgi_printf
To:
Omar Polo <op@omarpolo.com>
Cc:
gameoftrees@openbsd.org, Tracey Emery <tracey@traceyemery.net>
Date:
Mon, 15 Aug 2022 21:46:38 +1000

Download raw body.

Thread
On 22-08-11 05:06PM, Omar Polo wrote:
> On 2022/08/11 16:00:19 +0200, Omar Polo <op@omarpolo.com> wrote:
> > as suggested by Tracey, I took a bit further my idea of adding a
> > printf-like function in gotwebd.  Diff belows drops fcgi_gen_response
> > (used to "print" a string) and replace everything with fcgi_printf.
> > 
> > If fcgi_gen_response is preferred as a name I can change it.  I went
> > with a different name to make sure to catch and adapt every place
> > where it's called.  (i prefer fcgi_printf as name though)
> > 
> > I have this running on my instance and it seems to work.  I can't
> > visually spot differences in the pages and using the "View Page
> > Source" menu in firefox the html seems correct too.
> > 
> > If I've missed some NULL checks I guess I'll know pretty soon, but
> > after clicking around for a bit I haven't seen any "vprintf %s NULL"
> > in /var/log/messages.
> > 
> > The diff is pretty long to read and maybe even a bit boring, but on
> > the bright side it drops a lot of code (564 +, 1430 -).
> 
> there was a typo in gotweb_render_tags

That was a long diff to read! My eyes were crossing before I was even
halfway :)

It looks good to me. I haven't run it myself; it builds fine, but
I don't have gotweb setup to test yet (I should do sometime this
week). I have been playing with it on your site though--assuming it's
running with this patch--and that's working great!

A couple remarks:

  (1) I noticed in the diff lib we use the gcc extension to omit the
      middle operand in ternary ifs in quite a few places.  I just did
      a cursory scan of got and couldn't see it elsewhere _except_ it is
      used in gotwebd/got_operations.c. I'm not sure if you or stsp have
      a preference either way, but there are a few opportunities for it
      in this diff so thought I'd mention it.

  (2) See inline comments regarding omitted '\n' from some tags in the
      changed -fcgi_gen_response()/+fcgi_printf() lines. I'm pretty
      sure it doesn't matter, but I thought I'd ask for the sake of
      fidelity; please disregard if intentionally elided. Apart from
      that, there might be a couple missing closing div tags that I've
      also annotated inline.

I'll setup gotweb this week and run the patch myself if someone doesn't
ok before then. But I gave the diff a thorough read and it looks fine;
I particularly like all the '-' lines :)

> 
> diff /home/op/w/got
> commit - 3084a91bb165520582c5aa695e2c6717e09e5ba6
> path + /home/op/w/got
> blob - f6cb81448f5778d7872b537fd6b90838285c99ee
> file + gotwebd/fcgi.c
> --- gotwebd/fcgi.c
> +++ gotwebd/fcgi.c
> @@ -25,6 +25,7 @@
>  #include <errno.h>
>  #include <event.h>
>  #include <imsg.h>
> +#include <stdarg.h>
>  #include <stdlib.h>
>  #include <stdio.h>
>  #include <string.h>
> @@ -308,6 +309,27 @@ fcgi_timeout(int fd, short events, void *arg)
>  }
>  
>  int
> +fcgi_printf(struct request *c, 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) {
> +		log_warn("%s: asprintf", __func__);
> +		return -1;
> +	}
> +
> +	r = fcgi_gen_binary_response(c, str, r);
> +	free(str);
> +	return r;
> +}
> +
> +int
>  fcgi_gen_binary_response(struct request *c, const uint8_t *data, int len)
>  {
>  	int r;
> @@ -346,14 +368,6 @@ fcgi_gen_binary_response(struct request *c, const uint
>  	return 0;
>  }
>  
> -int
> -fcgi_gen_response(struct request *c, const char *data)
> -{
> -	if (data == NULL || *data == '\0')
> -		return 0;
> -	return fcgi_gen_binary_response(c, data, strlen(data));
> -}
> -
>  static int
>  send_response(struct request *c, int type, const uint8_t *data,
>      size_t len)
> blob - 1c274b225d0e710d16528c4b9970348bb3bec74e
> file + gotwebd/got_operations.c
> --- gotwebd/got_operations.c
> +++ gotwebd/got_operations.c
> @@ -829,10 +829,11 @@ got_output_repo_tree(struct request *c)
>  	struct got_reflist_head refs;
>  	struct got_tree_object *tree = NULL;
>  	struct repo_dir *repo_dir = t->repo_dir;
> +	const char *name, *index_page_str, *folder;
>  	char *id_str = NULL;
> -	char *path = NULL, *in_repo_path = NULL, *build_folder = NULL;
> -	char *modestr = NULL, *name = NULL;
> -	int nentries, i;
> +	char *path = NULL, *in_repo_path = NULL;
> +	char *modestr = NULL;

Could move *modestr = NULL to the above line:

	char *modestr = NULL, *path = NULL, *in_repo_path = NULL;

> +	int nentries, i, r;
>  
>  	TAILQ_INIT(&refs);
>  
> @@ -871,6 +872,9 @@ got_output_repo_tree(struct request *c)
>  
>  	nentries = got_object_tree_get_nentries(tree);
>  
> +	index_page_str = qs->index_page_str ? qs->index_page_str : "";
> +	folder = qs->folder ? qs->folder : "";
> +
>  	for (i = 0; i < nentries; i++) {
>  		struct got_tree_entry *te;
>  		mode_t mode;
> @@ -917,226 +921,55 @@ got_output_repo_tree(struct request *c)
>  			}
>  		}
>  
> -		name = strdup(got_tree_entry_get_name(te));
> -		if (name == NULL) {
> -			error = got_error_from_errno("strdup");
> -			goto done;
> -		}
>  		if (S_ISDIR(mode)) {
> -			if (asprintf(&build_folder, "%s/%s",
> -			    qs->folder ? qs->folder : "",
> -			    got_tree_entry_get_name(te)) == -1) {
> -				error = got_error_from_errno("asprintf");
> +			name = got_tree_entry_get_name(te);
> +			r = fcgi_printf(c,
> +			    "<div class='tree_wrapper'>\n"
> +			    "<div class='tree_line'>"
> +			    "<a class='diff_directory' "
> +			    "href='?index_page=%s&path=%s&action=tree"
> +			    "&commit=%s&folder=%s/%s'>%s%s</a>"
> +			    "</div>\n" /* .tree_line */
> +			    "<div class='tree_line_blank'>&nbsp;</div>\n"
> +			    "</div>", /* .tree_wrapper */

                                   ^^ \n was after </div> in removed
                                   line

> +			    index_page_str, qs->path, rc->commit_id,
> +			    folder, name, name, modestr);
> +			if (r == -1)
>  				goto done;
> -			}
> -
> -			if (fcgi_gen_response(c,
> -			    "<div class='tree_wrapper'>\n") == -1)
> -			goto done;
> -
> -			if (fcgi_gen_response(c, "<div class='tree_line'>") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "<a class='diff_directory' "
> -			    "href='?index_page=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "&path=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, qs->path) == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "&action=tree") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "&commit=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, rc->commit_id) == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "&folder=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, build_folder) == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "'>") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, name) == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, modestr) == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "</a>") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "</div>\n") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "<div class='tree_line_blank'>") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "&nbsp;") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "</div>\n") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "</div>\n") == -1)
> -				goto done;
> -
>  		} else {
> -			free(name);
> -			name = strdup(got_tree_entry_get_name(te));
> -			if (name == NULL) {
> -				error = got_error_from_errno("strdup");
> +			name = got_tree_entry_get_name(te);
> +			r = fcgi_printf(c,
> +			    "<div class='tree_wrapper'>\n"
> +			    "<div class='tree_line'>"
> +			    "<a href='?index_page=%s&path=%s&action=blob"
> +			    "&commit=%s&folder=%s&file=%s'>%s%s</a>"
> +			    "</div>" /* .tree_line */

                                   ^^ \n in removed line

> +			    "<div class='tree_line_blank'>"
> +			    "<a href='?index_page=%s&path=%s&action=commits"
> +			    "&commit=%s&folder=%s&file=%s'>commits</a>\n"
> +			    " | \n"
> +			    "<a href='?index_page=%s&path=%s&action=blame"
> +			    "&commit=%s&folder=%s&file=%s'>blame</a>\n"
> +			    "</div>"  /* .tree_line_blank */

                                   ^^ \n

> +			    "</div>", /* .tree_wrapper */

                                   ^^ \n

> +			    index_page_str, qs->path, rc->commit_id,
> +			    folder, name, name, modestr,
> +			    index_page_str, qs->path, rc->commit_id,
> +			    folder, name,
> +			    index_page_str, qs->path, rc->commit_id,
> +			    folder, name);
> +			if (r == -1)
>  				goto done;
> -			}
> -
> -			if (fcgi_gen_response(c,
> -			    "<div class='tree_wrapper'>\n") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "<div class='tree_line'>") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c,
> -			    "<a href='?index_page=") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&path=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, qs->path) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&action=blob") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&commit=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, rc->commit_id) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&folder=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, qs->folder) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&file=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, name) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "'>") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, name) == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, modestr) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "</a>") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "</div>\n") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "<div class='tree_line_blank'>") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c,
> -			    "<a href='?index_page=") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&path=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, qs->path) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&action=commits") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&commit=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, rc->commit_id) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&folder=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, qs->folder) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&file=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, name) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "'>") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "commits") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "</a>\n") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, " | \n") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c,
> -			    "<a href='?index_page=") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&path=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, qs->path) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&action=blame") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&commit=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, rc->commit_id) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&folder=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, qs->folder) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "&file=") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, name) == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "'>") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "blame") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "</a>\n") == -1)
> -				goto done;
> -
> -			if (fcgi_gen_response(c, "</div>\n") == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "</div>\n") == -1)
> -				goto done;
>  		}
>  		free(id_str);
>  		id_str = NULL;
> -		free(build_folder);
> -		build_folder = NULL;
> -		free(name);
> -		name = NULL;
>  		free(modestr);
>  		modestr = NULL;
>  	}
>  done:
>  	free(id_str);
> -	free(build_folder);
>  	free(modestr);
>  	free(path);
> -	free(name);
>  	got_ref_list_free(&refs);
>  	if (commit)
>  		got_object_commit_close(commit);
> @@ -1286,11 +1119,13 @@ got_gotweb_blame_cb(void *arg, int nlines, int lineno,
>  	struct transport *t = c->t;
>  	struct querystring *qs = t->qs;
>  	struct repo_dir *repo_dir = t->repo_dir;
> +	const char *index_page_str;
>  	char *line = NULL, *eline = NULL;
>  	size_t linesize = 0;
>  	off_t offset;
>  	struct tm tm;
>  	time_t committer_time;
> +	int r;
>  
>  	if (nlines != a->nlines ||
>  	    (lineno != -1 && lineno < 1) || lineno > a->nlines)
> @@ -1334,10 +1169,10 @@ got_gotweb_blame_cb(void *arg, int nlines, int lineno,
>  		goto done;
>  	}
>  
> +	index_page_str = qs->index_page_str ? qs->index_page_str : "";
> +
>  	while (bline->annotated) {
> -		int out_buff_size = 100;
>  		char *smallerthan, *at, *nl, *committer;
> -		char out_buff[out_buff_size];
>  		size_t len;
>  
>  		if (getline(&line, &linesize, a->f) == -1) {
> @@ -1361,68 +1196,29 @@ got_gotweb_blame_cb(void *arg, int nlines, int lineno,
>  		if (nl)
>  			*nl = '\0';
>  
> -		if (fcgi_gen_response(c, "<div class='blame_wrapper'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "<div class='blame_number'>") == -1)
> -			goto done;
> -		if (snprintf(out_buff, strlen(out_buff), "%.*d", a->nlines_prec,
> -		    a->lineno_cur) < 0)
> -			goto done;
> -		if (fcgi_gen_response(c, out_buff) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<div class='blame_hash'>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=diff&commit=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, bline->id_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (snprintf(out_buff, 10, "%.8s", bline->id_str) < 0)
> -			goto done;
> -		if (fcgi_gen_response(c, out_buff) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a></div>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<div class='blame_date'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, bline->datebuf) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<div class='blame_author'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, committer) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<div class='blame_code'>") == -1)
> -			goto done;
>  		err = gotweb_escape_html(&eline, line);
>  		if (err)
>  			goto done;
> -		if (fcgi_gen_response(c, eline) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>") == -1)
> -			goto done;
>  
> -		if (fcgi_gen_response(c, "</div>") == -1)
> +		r = fcgi_printf(c, "<div class='blame_wrapper'>"
> +		    "<div class='blame_number'>%.*d</div>"
> +		    "<div class='blame_hash'>"
> +		    "<a href='?index_page=%s&path=%s&action=diff&commit=%s'>"
> +		    "%.8s</a>"
> +		    "</div>"
> +		    "<div class='blame_date'>%s</div>"
> +		    "<div class='blame_author'>%s</div>"
> +		    "<div class='blame_code'>%s</div>"
> +		    "</div>",	/* .blame_wrapper */
> +		    a->nlines_prec, a->lineno_cur,
> +		    index_page_str, repo_dir->name, bline->id_str,
> +		    bline->id_str,
> +		    bline->datebuf,
> +		    committer,
> +		    eline);
> +		if (r == -1)
>  			goto done;
> +
>  		a->lineno_cur++;
>  		bline = &a->lines[a->lineno_cur - 1];
>  	}
> @@ -1767,12 +1563,7 @@ got_output_repo_diff(struct request *c)
>  				goto done;
>  			}
>  		}
> -		if (fcgi_gen_response(c, "<div class='diff_line' class='") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, color ? color : "") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> +
>  		newline = strchr(line, '\n');
>  		if (newline)
>  			*newline = '\0';
> @@ -1780,13 +1571,12 @@ got_output_repo_diff(struct request *c)
>  		error = gotweb_escape_html(&eline, line);
>  		if (error)
>  			goto done;
> -		if (fcgi_gen_response(c, eline) == -1)
> -			goto done;
> +
> +		fcgi_printf(c, "<div class='diff_line %s'>%s</div>",

                                                                  ^^ \n
> +		    color ? color : "", eline);
>  		free(eline);
>  		eline = NULL;
>  
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
>  		if (linelen > 0)
>  			wrlen = wrlen + linelen;
>  		free(color);
> blob - 4b3729bd8c2a9dba3031daeca4b3fea398ba2f7f
> file + gotwebd/gotweb.c
> --- gotwebd/gotweb.c
> +++ gotwebd/gotweb.c
> @@ -118,7 +118,7 @@ gotweb_process_request(struct request *c)
>  	struct querystring *qs = NULL;
>  	struct repo_dir *repo_dir = NULL;
>  	uint8_t err[] = "gotwebd experienced an error: ";
> -	int html = 0;
> +	int r, html = 0;
>  
>  	/* init the transport */
>  	error = gotweb_init_transport(&c->t);
> @@ -270,29 +270,27 @@ render:
>  		break;
>  	case ERR:
>  	default:
> -		if (fcgi_gen_response(c, "<div id='err_content'>") == -1)
> +		r = fcgi_printf(c, "<div id='err_content'>%s</div>\n",
> +		    "Erorr: Bad Querystring");
> +		if (r == -1)
>  			goto err;
> -		if (fcgi_gen_response(c, "Error: Bad Querystring\n") == -1)
> -			goto err;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto err;
>  		break;
>  	}
>  
>  	goto done;
>  err:
> -	if (html && fcgi_gen_response(c, "<div id='err_content'>") == -1)
> +	if (html && fcgi_printf(c, "<div id='err_content'>") == -1)
>  		return;
> -	if (fcgi_gen_response(c, err) == -1)
> +	if (fcgi_printf(c, "%s", err) == -1)
>  		return;
>  	if (error) {
> -		if (fcgi_gen_response(c, (uint8_t *)error->msg) == -1)
> +		if (fcgi_printf(c, "%s", error->msg) == -1)
>  			return;
>  	} else {
> -		if (fcgi_gen_response(c, "see daemon logs for details") == -1)
> +		if (fcgi_printf(c, "see daemon logs for details") == -1)
>  			return;
>  	}
> -	if (html && fcgi_gen_response(c, "</div>\n") == -1)
> +	if (html && fcgi_printf(c, "</div>\n") == -1)
>  		return;
>  done:
>  	if (c->t->repo != NULL && qs->action != INDEX)
> @@ -628,205 +626,123 @@ gotweb_free_transport(struct transport *t)
>  const struct got_error *
>  gotweb_render_content_type(struct request *c, const uint8_t *type)
>  {
> -	const struct got_error *error = NULL;
> -	char *h = NULL;
> -
> -	if (asprintf(&h, "Content-type: %s\r\n\r\n", type) == -1) {
> -		error = got_error_from_errno2("%s: asprintf", __func__);
> -		goto done;
> -	}
> -
> -	fcgi_gen_response(c, h);
> -done:
> -	free(h);
> -
> -	return error;
> +	fcgi_printf(c, "Content-Type: %s\r\n\r\n", type);
> +	return NULL;
>  }
>  
>  const struct got_error *
>  gotweb_render_content_type_file(struct request *c, const uint8_t *type,
>      char *file)
>  {
> -	const struct got_error *error = NULL;
> -	char *h = NULL;
> -
> -	if (asprintf(&h, "Content-type: %s\r\n"
> +	fcgi_printf(c, "Content-type: %s\r\n"
>  	    "Content-disposition: attachment; filename=%s\r\n\r\n",
> -	    type, file) == -1) {
> -		error = got_error_from_errno2("%s: asprintf", __func__);
> -		goto done;
> -	}
> -
> -	fcgi_gen_response(c, h);
> -done:
> -	free(h);
> -
> -	return error;
> +	    type, file);
> +	return NULL;
>  }
>  
>  static const struct got_error *
>  gotweb_render_header(struct request *c)
>  {
> -	const struct got_error *error = NULL;
>  	struct server *srv = c->srv;
>  	struct querystring *qs = c->t->qs;
> -	char *title = NULL, *droot = NULL, *css = NULL, *gotlink = NULL;
> -	char *gotimg = NULL, *sitelink = NULL, *summlink = NULL;
> +	char droot[PATH_MAX];
> +	int r;
>  
>  	if (strlen(c->document_root) > 0) {
> -		if (asprintf(&droot, "/%s/", c->document_root) == -1) {
> -			error = got_error_from_errno2("%s: asprintf", __func__);
> -			goto done;
> -		}
> -	} else {
> -		if (asprintf(&droot, "/") == -1) {
> -			error = got_error_from_errno2("%s: asprintf", __func__);
> -			goto done;
> -		}
> -	}
> +		r = snprintf(droot, sizeof(droot), "/%s/", c->document_root);
> +		if (r < 0 || (size_t)r >= sizeof(droot))
> +			return got_error(GOT_ERR_NO_SPACE);
> +	} else
> +		strlcpy(droot, "/", sizeof(droot));
>  
> -	if (asprintf(&title, "<title>%s</title>\n", srv->site_name) == -1) {
> -		error = got_error_from_errno2("%s: asprintf", __func__);
> +	r = fcgi_printf(c, "<!doctype html>\n"
> +	    "<head>\n"
> +	    "<title>%s</title>\n"
> +	    "<meta charset='utf-8' />\n"
> +	    "<meta name='viewport' content='initial-scale=.75' />\n"
> +	    "<meta name='msapplication-TileColor' content='#da532c' />\n"
> +	    "<meta name='theme-color' content='#ffffff'/>\n"
> +	    "<link rel='apple-touch-icon' sizes='180x180'"
> +	    " href='/apple-touch-icon.png' />\n"
> +	    "<link rel='icon' type='image/png' sizes='32x32'"
> +	    " href='/favicon-32x32.png' />\n"
> +	    "<link rel='icon' type='image/png' sizes='16x16'"
> +	    " href='/favicon-16x16.png' />\n"
> +	    "<link rel='manifest' href='/site.webmanifest'/>\n"
> +	    "<link rel='mask-icon' href='/safari-pinned-tab.svg' />\n"
> +	    "<link rel='stylesheet' type='text/css' href='%s%s' />\n"
> +	    "</head>\n"
> +	    "<body>\n"
> +	    "<div id='gw_body'>\n"
> +	    "<div id='header'>\n"
> +	    "<div id='got_link'>"
> +	    "<a href='%s' target='_sotd'>"
> +	    "<img src='%s%s' alt='logo' id='logo' />"
> +	    "</a>\n"
> +	    "</div>\n"		/* #got_link */
> +	    "</div>\n"		/* #header */
> +	    "<div id='site_path'>\n"
> +	    "<div id='site_link'>\n"
> +	    "<a href='/%s?index_page=%d' alt='sitelink'>%s</a>",
> +	    srv->site_name,
> +	    droot, srv->custom_css,
> +	    srv->logo_url,
> +	    droot, srv->logo,
> +	    c->document_root, qs->index_page, srv->site_link);
> +	if (r == -1)
>  		goto done;
> -	}
> -	if (asprintf(&css,
> -	    "<link rel='stylesheet' type='text/css' href='%s%s'/>\n",
> -	    droot, srv->custom_css) == -1) {
> -		error = got_error_from_errno2("%s: asprintf", __func__);
> -		goto done;
> -	}
> -	if (asprintf(&gotlink, "<a href='%s' target='_sotd'>",
> -	    srv->logo_url) == -1) {
> -		error = got_error_from_errno2("%s: asprintf", __func__);
> -		goto done;
> -	}
> -	if (asprintf(&gotimg, "<img src='%s%s' alt='logo' id='logo'/></a>",
> -	    droot, srv->logo) == -1) {
> -		error = got_error_from_errno2("%s: asprintf", __func__);
> -		goto done;
> -	}
> -	if (asprintf(&sitelink, "<a href='/%s?index_page=%d' "
> -	    "alt='sitelink'>%s</a>", c->document_root, qs->index_page,
> -	    srv->site_link) == -1) {
> -		error = got_error_from_errno2("%s: asprintf", __func__);
> -		goto done;
> -	}
> -	if (asprintf(&summlink, "<a href='/%s?index_page=%d&path=%s"
> -	    "&action=summary' alt='summlink'>%s</a>", c->document_root,
> -	    qs->index_page, qs->path, qs->path) == -1) {
> -		error = got_error_from_errno2("%s: asprintf", __func__);
> -		goto done;
> -	}
>  
> -	if (fcgi_gen_response(c, "<!DOCTYPE html>\n<head>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, title) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<meta name='viewport' "
> -	    "content='initial-scale=.75, user-scalable=yes'/>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<meta charset='utf-8'/>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<meta name='msapplication-TileColor' "
> -	    "content='#da532c'/>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c,
> -	    "<meta name='theme-color' content='#ffffff'/>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<link rel='apple-touch-icon' sizes='180x180' "
> -	    "href='/apple-touch-icon.png'/>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c,
> -	    "<link rel='icon' type='image/png' sizes='32x32' "
> -	    "href='/favicon-32x32.png'/>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<link rel='icon' type='image/png' "
> -	    "sizes='16x16' href='/favicon-16x16.png'/>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<link rel='manifest' "
> -	    "href='/site.webmanifest'/>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<link rel='mask-icon' "
> -	    "href='/safari-pinned-tab.svg'/>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, css) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</head>\n<body>\n<div id='gw_body'>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c,
> -	    "<div id='header'>\n<div id='got_link'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, gotlink) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, gotimg) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c,
> -	    "<div id='site_path'>\n<div id='site_link'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, sitelink) == -1)
> -		goto done;
>  	if (qs != NULL) {
>  		if (qs->path != NULL) {
> -			if (fcgi_gen_response(c, " / ") == -1)
> +			r = fcgi_printf(c, " / "
> +			    "<a href='/%s?index_page=%d&path=%s&action=summary'"
> +			    " alt='summlink'>%s</a>",
> +			    c->document_root, qs->index_page, qs->path,
> +			    qs->path);
> +			if (r == -1)
>  				goto done;
> -			if (fcgi_gen_response(c, summlink) == -1)
> -				goto done;
>  		}
>  		if (qs->action != INDEX) {
> -			if (fcgi_gen_response(c, " / ") == -1)
> -				goto done;
> -			switch(qs->action) {
> -			case(BLAME):
> -				if (fcgi_gen_response(c, "blame") == -1)
> -					goto done;
> +			const char *action = "";
> +
> +			switch (qs->action) {
> +			case BLAME:
> +				action = "blame";
>  				break;
> -			case(BRIEFS):
> -				if (fcgi_gen_response(c, "briefs") == -1)
> -					goto done;
> +			case BRIEFS:
> +				action = "briefs";
>  				break;
> -			case(COMMITS):
> -				if (fcgi_gen_response(c, "commits") == -1)
> -					goto done;
> +			case COMMITS:
> +				action = "commits";
>  				break;
> -			case(DIFF):
> -				if (fcgi_gen_response(c, "diff") == -1)
> -					goto done;
> +			case DIFF:
> +				action = "diff";
>  				break;
> -			case(SUMMARY):
> -				if (fcgi_gen_response(c, "summary") == -1)
> -					goto done;
> +			case SUMMARY:
> +				action = "summary";
>  				break;
> -			case(TAG):
> -				if (fcgi_gen_response(c, "tag") == -1)
> -					goto done;
> +			case TAG:
> +				action = "tag";
>  				break;
> -			case(TAGS):
> -				if (fcgi_gen_response(c, "tags") == -1)
> -					goto done;
> +			case TAGS:
> +				action = "tags";
>  				break;
> -			case(TREE):
> -				if (fcgi_gen_response(c, "tree") == -1)
> -					goto done;
> +			case TREE:
> +				action = "tree";
>  				break;
> -			default:
> -				break;
>  			}
> +
> +			if (fcgi_printf(c, " / %s", action) == -1)
> +				goto done;
>  		}
> -
>  	}
> -	fcgi_gen_response(c, "</div>\n</div>\n<div id='content'>\n");

                                    ^^      ^^                  ^^
                         these three \n weren't copied
                         here vv
> +
> +	fcgi_printf(c, "</div>"	/* #site_path */
> +	    "</div>"		/* #site_link */
> +	    "<div id='content'>");
> +
>  done:
> -	free(title);
> -	free(droot);
> -	free(css);
> -	free(gotlink);
> -	free(gotimg);
> -	free(sitelink);
> -	free(summlink);
> -
> -	return error;
> +	return NULL;
>  }
>  
>  static const struct got_error *
> @@ -834,26 +750,23 @@ gotweb_render_footer(struct request *c)
>  {
>  	const struct got_error *error = NULL;
>  	struct server *srv = c->srv;
> -	char *siteowner = NULL;
> +	const char *siteowner = "&nbsp;";
> +	char *escaped_owner = NULL;
>  
> -	if (fcgi_gen_response(c, "<div id='site_owner_wrapper'>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='site_owner'>") == -1)
> -		goto done;
>  	if (srv->show_site_owner) {
> -		error = gotweb_escape_html(&siteowner, srv->site_owner);
> +		error = gotweb_escape_html(&escaped_owner, srv->site_owner);
>  		if (error)
> -			goto done;
> -		if (fcgi_gen_response(c, siteowner) == -1)
> -			goto done;
> -	} else
> -		if (fcgi_gen_response(c, "&nbsp;") == -1)
> -			goto done;
> -	fcgi_gen_response(c, "</div>\n</div>\n</div>\n</body>\n</html>");
> -done:
> -	free(siteowner);
> +			return error;
> +		siteowner = escaped_owner;
> +	}
>  
> -	return error;
> +	fcgi_printf(c, "<div id='site_owner_wrapper'>\n"
> +	    "<div id='site_owner'>%s</div>"
> +	    "</div>\n</div>\n</div>\n</body>\n</html>",
> +	    siteowner);
> +
> +	free(escaped_owner);
> +	return NULL;
>  }
>  
>  static const struct got_error *
> @@ -864,12 +777,11 @@ gotweb_render_navs(struct request *c)
>  	struct querystring *qs = t->qs;
>  	struct server *srv = c->srv;
>  	char *nhref = NULL, *phref = NULL;
> -	int disp = 0;
> +	int r, disp = 0;
>  
> -	if (fcgi_gen_response(c, "<div id='np_wrapper'>\n") == -1)
> +	r = fcgi_printf(c, "<div id='np_wrapper'>\n<div id='nav_prev'>");
> +	if (r == -1)
>  		goto done;
> -	if (fcgi_gen_response(c, "<div id='nav_prev'>") == -1)
> -		goto done;
>  
>  	switch(qs->action) {
>  	case INDEX:
> @@ -933,17 +845,15 @@ gotweb_render_navs(struct request *c)
>  	}
>  
>  	if (disp) {
> -		if (fcgi_gen_response(c, "<a href='?") == -1)
> -			goto  done;
> -		if (fcgi_gen_response(c, phref) == -1)
> +		r = fcgi_printf(c, "<a href='?%s'>Previous</a>", phref);
> +		if (r == -1)
>  			goto done;
> -		if (fcgi_gen_response(c, "'>Previous</a>") == -1)
> -			goto done;
>  	}
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> +
> +	r = fcgi_printf(c, "</div>\n"	/* #nav_prev */
> +	    "<div id='nav_next'>");
> +	if (r == -1)
>  		goto done;
> -	if (fcgi_gen_response(c, "<div id='nav_next'>") == -1)
> -		goto done;
>  
>  	disp = 0;
>  
> @@ -1007,14 +917,11 @@ gotweb_render_navs(struct request *c)
>  		break;
>  	}
>  	if (disp) {
> -		if (fcgi_gen_response(c, "<a href='?") == -1)
> +		r = fcgi_printf(c, "<a href='?%s'>Next</a>", nhref);
> +		if (r == -1)
>  			goto done;
> -		if (fcgi_gen_response(c, nhref) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>Next</a>") == -1)
> -			goto done;
>  	}
> -	fcgi_gen_response(c, "</div>\n");
> +	fcgi_printf(c, "</div>\n");
>  done:
>  	free(t->next_id);
>  	t->next_id = NULL;
> @@ -1035,10 +942,14 @@ gotweb_render_index(struct request *c)
>  	struct repo_dir *repo_dir = NULL;
>  	DIR *d;
>  	struct dirent **sd_dent;
> +	const char *index_page_str;
>  	char *c_path = NULL;
>  	struct stat st;
>  	unsigned int d_cnt, d_i, d_disp = 0;
> +	int r;
>  
> +	index_page_str = qs->index_page_str ? qs->index_page_str : "";
> +
>  	d = opendir(srv->repos_path);
>  	if (d == NULL) {
>  		error = got_error_from_errno2("opendir", srv->repos_path);
> @@ -1070,24 +981,24 @@ gotweb_render_index(struct request *c)
>  		c_path = NULL;
>  	}
>  
> -	if (fcgi_gen_response(c, "<div id='index_header'>\n") == -1)
> +	r = fcgi_printf(c, "<div id='index_header'>\n"
> +	    "<div id='index_header_project'>Project</div>\n");
> +	if (r == -1)
>  		goto done;
> -	if (fcgi_gen_response(c,
> -	    "<div id='index_header_project'>Project</div>\n") == -1)
> -		goto done;
> +
>  	if (srv->show_repo_description)
> -		if (fcgi_gen_response(c, "<div id='index_header_description'>"
> +		if (fcgi_printf(c, "<div id='index_header_description'>"
>  		    "Description</div>\n") == -1)
>  			goto done;
>  	if (srv->show_repo_owner)
> -		if (fcgi_gen_response(c, "<div id='index_header_owner'>"
> +		if (fcgi_printf(c, "<div id='index_header_owner'>"
>  		    "Owner</div>\n") == -1)
>  			goto done;
>  	if (srv->show_repo_age)
> -		if (fcgi_gen_response(c, "<div id='index_header_age'>"
> +		if (fcgi_printf(c, "<div id='index_header_age'>"
>  		    "Last Change</div>\n") == -1)
>  			goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> +	if (fcgi_printf(c, "</div>\n") == -1) /* #index_header */
>  		goto done;
>  
>  	for (d_i = 0; d_i < d_cnt; d_i++) {
> @@ -1128,149 +1039,69 @@ gotweb_render_index(struct request *c)
>  render:
>  		d_disp++;
>  		t->prev_disp++;
> -		if (fcgi_gen_response(c, "<div class='index_wrapper'>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "<div class='index_project'>") == -1)
> -			goto done;
>  
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> +		r = fcgi_printf(c, "<div class='index_wrapper'>\n"
> +		    "<div class='index_project'>"
> +		    "<a href='?index_page=%s&path=%s&action=summary'>"
> +		    " %s "
> +		    "</a>"
> +		    "</div>",	/* .index_project */
> +		    index_page_str, repo_dir->name,
> +		    repo_dir->name);
> +		if (r == -1)
>  			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=summary'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
>  
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -
>  		if (srv->show_repo_description) {
> -			if (fcgi_gen_response(c,
> -			    "<div class='index_project_description'>\n") == -1)
> +			r = fcgi_printf(c,
> +			    "<div class='index_project_description'>\n"
> +			    "%s</div>\n", repo_dir->description);
> +			if (r == -1)
>  				goto done;
> -			if (fcgi_gen_response(c, repo_dir->description) == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "</div>\n") == -1)
> -				goto done;
>  		}
>  
>  		if (srv->show_repo_owner) {
> -			if (fcgi_gen_response(c,
> -			    "<div class='index_project_owner'>") == -1)
> +			r = fcgi_printf(c, "<div class='index_project_owner'>"
> +			    "%s</div>\n", repo_dir->owner);
> +			if (r == -1)
>  				goto done;
> -			if (fcgi_gen_response(c, repo_dir->owner) == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "</div>\n") == -1)
> -				goto done;
>  		}
>  
>  		if (srv->show_repo_age) {
> -			if (fcgi_gen_response(c,
> -			    "<div class='index_project_age'>") == -1)
> +			r = fcgi_printf(c, "<div class='index_project_age'>"
> +			    "%s</div>\n", repo_dir->age);
> +			if (r == -1)
>  				goto done;
> -			if (fcgi_gen_response(c, repo_dir->age) == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, "</div>\n") == -1)
> -				goto done;
>  		}
>  
> -		if (fcgi_gen_response(c, "<div class='navs_wrapper'>") == -1)
> +		r = fcgi_printf(c, "<div class='navs_wrapper'>"
> +		    "<div class='navs'>"
> +		    "<a href='?index_page=%s&path=%s&action=summary'>"
> +		    "summary"
> +		    "</a> | "
> +		    "<a href='?index_page=%s&path=%s&action=briefs'>"
> +		    "commit briefs"
> +		    "</a> | "
> +		    "<a href='?index_page=%s&path=%s&action=commits'>"
> +		    "commits"
> +		    "</a> | "
> +		    "<a href='?index_page=%s&path=%s&action=tags'>"
> +		    "tags"
> +		    "</a> | "
> +		    "<a href='?index_page=%s&path=%s&action=tree'>"
> +		    "tree"
> +		    "</a>"
> +		    "</div>"	/* .navs */
> +		    "<div class='dotted_line'></div>\n"
> +		    "</div>\n"	/* .navs_wrapper */
> +		    "</div>\n",	/* .index_wrapper */
> +		    index_page_str, repo_dir->name,
> +		    index_page_str, repo_dir->name,
> +		    index_page_str, repo_dir->name,
> +		    index_page_str, repo_dir->name,
> +		    index_page_str, repo_dir->name);
> +		if (r == -1)
>  			goto done;
> -		if (fcgi_gen_response(c, "<div class='navs'>") == -1)
> -			goto done;;
>  
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=summary'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "summary") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a> | ") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=briefs'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "commit briefs") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a> | ") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=commits'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "commits") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a> | ") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=tags'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "tags") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a> | ") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=tree'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "tree") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "</div>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c,
> -		    "<div class='dotted_line'></div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -
>  		gotweb_free_repo_dir(repo_dir);
>  		repo_dir = NULL;
>  		error = got_repo_close(t->repo);
> @@ -1292,7 +1123,7 @@ render:
>  	if (error)
>  		goto done;
>  div:
> -	fcgi_gen_response(c, "</div>\n");
> +	/* fcgi_printf(c, "<!-- extra? --></div>\n"); */
>  done:
>  	if (d != NULL && closedir(d) == EOF && error == NULL)
>  		error = got_error_from_errno("closedir");
> @@ -1306,6 +1137,7 @@ gotweb_render_blame(struct request *c)
>  	struct transport *t = c->t;
>  	struct repo_commit *rc = NULL;
>  	char *age = NULL;
> +	int r;
>  
>  	error = got_get_repo_commits(c, 1);
>  	if (error)
> @@ -1317,58 +1149,32 @@ gotweb_render_blame(struct request *c)
>  	if (error)
>  		goto done;
>  
> -	if (fcgi_gen_response(c, "<div id='blame_title_wrapper'>\n") == -1)
> +	r = fcgi_printf(c, "<div id='blame_title_wrapper'>\n"
> +	    "<div id='blame_title'>Blame</div>\n"
> +	    "</div>"		/* #blame_title_wrapper */

                   ^^ \n

> +	    "<div id='blame_content'>\n"
> +	    "<div id='blame_header_wrapper'>\n"
> +	    "<div id='blame_header'>\n"
> +	    "<div class='header_age_title'>Date:</div>\n"
> +	    "<div class='header_age'>%s</div>"
> +	    "<div id='header_commit_msg_title'>Message:</div>\n"
> +	    "<div id='header_commit_msg'>%s</div>"

                                                 ^^ \n

> +	    "</div>"		/* #blame_header */

                   ^^ \n

> +	    "</div>"		/* #blame_header_wrapper */

                   ^^ \n

> +	    "<div class='dotted_line'></div>\n"
> +	    "<div id='blame'>\n",
> +	    age ? age : "",
> +	    rc->commit_msg);
> +	if (r == -1)
>  		goto done;
> -	if (fcgi_gen_response(c, "<div id='blame_title'>Blame</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
>  
> -	if (fcgi_gen_response(c, "<div id='blame_content'>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div id='blame_header_wrapper'>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='blame_header'>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div class='header_age_title'>Date:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div class='header_age'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, age ? age : "") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div id='header_commit_msg_title'>Message:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='header_commit_msg'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, rc->commit_msg) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div class='dotted_line'></div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='blame'>\n") == -1)
> -		goto done;
> -
>  	error = got_output_file_blame(c);
>  	if (error)
>  		goto done;
>  
> -	fcgi_gen_response(c, "</div>\n");
> +	fcgi_printf(c, "</div>\n"	/* #blame */
> +	    "</div>\n");		/* #blame_content */

             ^^^^^^ this second /div was after done:

>  done:
> -	fcgi_gen_response(c, "</div>\n");
>  	return error;
>  }
>  
> @@ -1381,18 +1187,18 @@ gotweb_render_briefs(struct request *c)
>  	struct transport *t = c->t;
>  	struct querystring *qs = t->qs;
>  	struct repo_dir *repo_dir = t->repo_dir;
> +	const char *index_page_str;
>  	char *smallerthan, *newline;
>  	char *age = NULL;
> +	int r;
>  
> -	if (fcgi_gen_response(c, "<div id='briefs_title_wrapper'>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c,
> -	    "<div id='briefs_title'>Commit Briefs</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> +	index_page_str = qs->index_page_str ? qs->index_page_str : "";
>  
> -	if (fcgi_gen_response(c, "<div id='briefs_content'>\n") == -1)
> +	r = fcgi_printf(c, "<div id='briefs_title_wrapper'>\n"
> +	    "<div id='briefs_title'>Commit Briefs</div>\n"
> +	    "</div>"	/* #briefs_title_wrapper */

                   ^^ \n

> +	    "<div id='briefs_content'>\n");
> +	if (r == -1)
>  		goto done;
>  
>  	if (qs->action == SUMMARY) {
> @@ -1407,123 +1213,52 @@ gotweb_render_briefs(struct request *c)
>  		error = gotweb_get_time_str(&age, rc->committer_time, TM_DIFF);
>  		if (error)
>  			goto done;
> -		if (fcgi_gen_response(c, "<div class='briefs_age'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, age ? age : "") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
>  
> -		if (fcgi_gen_response(c, "<div class='briefs_author'>") == -1)
> -			goto done;
>  		smallerthan = strchr(rc->author, '<');
>  		if (smallerthan)
>  			*smallerthan = '\0';
> -		if (fcgi_gen_response(c, rc->author) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
>  
> -		if (fcgi_gen_response(c, "<div class='briefs_log'>") == -1)
> -			goto done;
>  		newline = strchr(rc->commit_msg, '\n');
>  		if (newline)
>  			*newline = '\0';
>  
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> +		r = fcgi_printf(c, "<div class='briefs_age'>%s</div>\n"
> +		    "<div class='briefs_author'>%s</div>"

                                                        ^^ \n

> +		    "<div class='briefs_log'>"
> +		    "<a href='?index_page=%s&path=%s&action=diff&commit=%s"
> +		    "&headref=%s'>%s</a>",
> +		    age ? age : "",
> +		    rc->author,
> +		    index_page_str, repo_dir->name, rc->commit_id, qs->headref,
> +		    rc->commit_msg);
> +		if (r == -1)
>  			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=diff&commit=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, rc->commit_id) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&headref=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->headref) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, rc->commit_msg) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
> +
>  		if (rc->refs_str) {
> -			if (fcgi_gen_response(c,
> -			    " <span class='refs_str'>(") == -1)
> +			r = fcgi_printf(c,
> +			    " <span class='refs_str'>(%s)</span>",
> +			    rc->refs_str);
> +			if (r == -1)
>  				goto done;
> -			if (fcgi_gen_response(c, rc->refs_str) == -1)
> -				goto done;
> -			if (fcgi_gen_response(c, ")</span>") == -1)
> -				goto done;
>  		}
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> +		if (fcgi_printf(c, "</div>\n") == -1) /* .briefs_log */
>  			goto done;
>  
> -		if (fcgi_gen_response(c, "<div class='navs_wrapper'>\n") == -1)
> +		r = fcgi_printf(c, "<div class='navs_wrapper'>\n"
> +		    "<div class='navs'>"
> +		    "<a href='?index_page=%s&path=%s&action=diff&commit=%s"
> +		    "&headref=%s'>diff</a>"
> +		    " | "
> +		    "<a href='?index_page=%s&path=%s&action=tree&commit=%s"
> +		    "&headref=%s'>tree</a>"
> +		    "</div>"	/* .navs */

                           ^^ \n

> +		    "</div>"	/* .navs_wrapper */

                           ^^ \n

> +		    "<div class='dotted_line'></div>",

                                                    ^^ \n

> +		    index_page_str, repo_dir->name, rc->commit_id, qs->headref,
> +		    index_page_str, repo_dir->name, rc->commit_id, qs->headref);
> +		if (r == -1)
>  			goto done;
> -		if (fcgi_gen_response(c, "<div class='navs'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=diff&commit=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, rc->commit_id) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&headref=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->headref) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "diff") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
>  
> -		if (fcgi_gen_response(c, " | ") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=tree&commit=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, rc->commit_id) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&headref=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->headref) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "tree") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c,
> -		    "<div class='dotted_line'></div>\n") == -1)
> -			goto done;
> -
>  		free(age);
>  		age = NULL;
>  	}
> @@ -1533,7 +1268,7 @@ gotweb_render_briefs(struct request *c)
>  		if (error)
>  			goto done;
>  	}
> -	fcgi_gen_response(c, "</div>\n");
> +	fcgi_printf(c, "</div>\n"); /* #briefs_content */
>  done:
>  	free(age);
>  	return error;
> @@ -1548,18 +1283,17 @@ gotweb_render_commits(struct request *c)
>  	struct transport *t = c->t;
>  	struct querystring *qs = t->qs;
>  	struct repo_dir *repo_dir = t->repo_dir;
> +	const char *index_page_str;
>  	char *age = NULL, *author = NULL;
> -	/* int commit_found = 0; */
> +	int r;
>  
> -	if (fcgi_gen_response(c, "<div class='commits_title_wrapper'>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c,
> -	    "<div class='commits_title'>Commits</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> +	index_page_str = qs->index_page_str ? qs->index_page_str : "";
>  
> -	if (fcgi_gen_response(c, "<div class='commits_content'>\n") == -1)
> +	r = fcgi_printf(c, "<div class='commits_title_wrapper'>\n"
> +	    "<div class='commits_title'>Commits</div>\n"
> +	    "</div>\n"		/* .commits_title_wrapper */
> +	    "<div class='commits_content'>\n");
> +	if (r == -1)
>  		goto done;
>  
>  	error = got_get_repo_commits(c, srv->max_commits_display);
> @@ -1574,113 +1308,38 @@ gotweb_render_commits(struct request *c)
>  		if (error)
>  			goto done;
>  
> -		if (fcgi_gen_response(c,
> -		    "<div class='commits_header_wrapper'>\n") == -1)
> +		r = fcgi_printf(c, "<div class='commits_header_wrapper'>\n"
> +		    "<div class='commits_header'>\n"
> +		    "<div class='header_commit_title'>Commit:</div>"

                                                                   ^^ \n

> +		    "<div class='header_commit'>%s</div>\n"
> +		    "<div class='header_author_title'>Author:</div>"

                                                                   ^^ \n

> +		    "<div class='header_author'>%s</div>\n"
> +		    "<div class='header_age_title'>Date:</div>"

                                                              ^^ \n

> +		    "<div class='header_age'>%s</div>"

                                                     ^^ \n

> +		    "</div>"	/* .commits_header */

                           ^^ \n

> +		    "</div>"	/* .commits_header_wrapper */

                           ^^ \n

> +		    "<div class='dotted_line'></div>\n"
> +		    "<div class='commit'>\n%s</div>",

                                                   ^^ \n

> +		    rc->commit_id,
> +		    author ? author : "",
> +		    age ? age : "",
> +		    rc->commit_msg);
> +		if (r == -1)
>  			goto done;
> -		if (fcgi_gen_response(c, "<div class='commits_header'>\n") == -1)
> -			goto done;

</div> missing between div class='commit' and div class='navs_wrapper'?
see below xxx

> +		r = fcgi_printf(c, "<div class='navs_wrapper'>\n"
> +		    "<div class='navs'>"
> +		    "<a href='?index_page=%s&path=%s&action=diff&commit=%s>"
> +		    "diff</a>"
> +		    " | "
> +		    "<a href='?index_page=%s&path=%s&action=tree&commit=%s>"
> +		    "tree</a>"
> +		    "</div>"	/* .navs */

                           ^^ \n

> +		    "</div>"	/* .navs_wrapper */

                           ^^ \n

> +		    "<div class='dotted_line'></div>\n",
> +		    index_page_str, repo_dir->name, rc->commit_id,
> +		    index_page_str, repo_dir->name, rc->commit_id);
>  
> -		if (fcgi_gen_response(c, "<div class='header_commit_title'>Commit:"
> -		    "</div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "<div class='header_commit'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, rc->commit_id) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<div class='header_author_title'>Author:"
> -		    "</div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "<div class='header_author'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, author ? author : "") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<div class='header_age_title'>Date:"
> -		    "</div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "<div class='header_age'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, age ? age : "") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c,
> -		    "<div class='dotted_line'></div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "<div class='commit'>\n") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, rc->commit_msg) == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;

xxx
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
xxx

> -
> -		if (fcgi_gen_response(c, "<div class='navs_wrapper'>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "<div class='navs'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=diff&commit=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, rc->commit_id) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "diff") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, " | ") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=tree&commit=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, rc->commit_id) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "tree") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c,
> -		    "<div class='dotted_line'></div>\n") == -1)
> -			goto done;
>  		free(age);
>  		age = NULL;
>  		free(author);
> @@ -1692,8 +1351,7 @@ gotweb_render_commits(struct request *c)
>  		if (error)
>  			goto done;
>  	}
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> +	fcgi_printf(c, "</div>\n"); /* .commits_content */
>  done:
>  	free(age);
>  	return error;
> @@ -1708,8 +1366,12 @@ gotweb_render_branches(struct request *c)
>  	struct transport *t = c->t;
>  	struct querystring *qs = t->qs;
>  	struct got_repository *repo = t->repo;
> +	const char *index_page_str;
>  	char *age = NULL;
> +	int r;
>  
> +	index_page_str = qs->index_page_str ? qs->index_page_str : "";
> +
>  	TAILQ_INIT(&refs);
>  
>  	error = got_ref_list(&refs, repo, "refs/heads",
> @@ -1717,17 +1379,13 @@ gotweb_render_branches(struct request *c)
>  	if (error)
>  		goto done;
>  
> -	if (fcgi_gen_response(c, "<div id='branches_title_wrapper'>\n") == -1)
> +	r = fcgi_printf(c, "<div id='branches_title_wrapper'>\n"
> +	    "<div id='branches_title'>Branches</div>\n"
> +	    "</div>"	/* #branches_title_wrapper */

                   ^^ \n

> +	    "<div id='branches_content'>\n");
> +	if (r == -1)
>  		goto done;
> -	if (fcgi_gen_response(c,
> -	    "<div id='branches_title'>Branches</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
>  
> -	if (fcgi_gen_response(c, "<div id='branches_content'>\n") == -1)
> -		goto done;
> -
>  	TAILQ_FOREACH(re, &refs, entry) {
>  		char *refname = NULL;
>  
> @@ -1750,132 +1408,42 @@ gotweb_render_branches(struct request *c)
>  		if (strncmp(refname, "refs/heads/", 11) == 0)
>  			refname += 11;
>  
> -		if (fcgi_gen_response(c, "<div class='branches_wrapper'>") == -1)
> +		r = fcgi_printf(c, "<div class='branches_wrapper'>\n"

                                     no \n in fcgi_gen_response() ^^

> +		    "<div class='branches_age'>%s</div>\n"
> +		    "<div class='branches_space'>&nbsp;</div>\n"
> +		    "<div class='branch'>"
> +		    "<a href='?index_page=%s&path=%s&action=summary&headref=%s'>"
> +		    "%s</a>"
> +		    "</div>"	/* .branch */

                           ^^ \n

> +		    "<div class='navs_wrapper'>\n"
> +		    "<div class='navs'>"
> +		    "<a href='?index_page=%s&path=%s&action=summary&headref=%s'>"
> +		    "summary</a>"
> +		    " | "
> +		    "<a href='?index_page=%s&path=%s&action=briefs&headref=%s'>"
> +		    "commit briefs</a>"
> +		    " | "
> +		    "<a href='?index_page=%s&path=%s&action=commits&headref=%s'>"
> +		    "commits</a>"
> +		    "</div>"	/* .navs */

                           ^^ \n

> +		    "</div>"	/* .navs_wrapper */

                           ^^ \n

> +		    "<div class='dotted_line'></div>\n"
> +		    "</div>"	/* .branches_wrapper */

                           ^^ \n

> +		    ,
> +		    age ? age : "",
> +		    index_page_str, qs->path, refname,
> +		    refname,
> +		    index_page_str, qs->path, refname,
> +		    index_page_str, qs->path, refname,
> +		    index_page_str, qs->path, refname);
> +		if (r == -1)
>  			goto done;
>  
> -		if (fcgi_gen_response(c, "<div class='branches_age'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, age ? age : "") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<div class='branches_space'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&nbsp;") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<div class='branch'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->path) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=summary&headref=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, refname) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, refname) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<div class='navs_wrapper'>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "<div class='navs'>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->path) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=summary&headref=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, refname) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "summary") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, " | ") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->path) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=briefs&headref=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, refname) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "commit briefs") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, " | ") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->path) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=commits&headref=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, refname) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "commits") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c,
> -		    "<div class='dotted_line'></div>\n") == -1)
> -			goto done;
> -
> -		/* branches_wrapper */
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -
>  		free(age);
>  		age = NULL;
>  
>  	}
> -	fcgi_gen_response(c, "</div>\n");
> +	fcgi_printf(c, "</div>\n"); /* #branches_content */
>  done:
>  	return error;
>  }
> @@ -1887,6 +1455,7 @@ gotweb_render_tree(struct request *c)
>  	struct transport *t = c->t;
>  	struct repo_commit *rc = NULL;
>  	char *age = NULL;
> +	int r;
>  
>  	error = got_get_repo_commits(c, 1);
>  	if (error)
> @@ -1898,67 +1467,34 @@ gotweb_render_tree(struct request *c)
>  	if (error)
>  		goto done;
>  
> -	if (fcgi_gen_response(c, "<div id='tree_title_wrapper'>\n") == -1)
> +	r = fcgi_printf(c, "<div id='tree_title_wrapper'>\n"
> +	    "<div id='tree_title'>Tree</div>\n"
> +	    "</div>\n"		/* #tree_title_wrapper */
> +	    "<div id='tree_content'>\n"
> +	    "<div id='tree_header_wrapper'>\n"
> +	    "<div id='tree_header'>\n"
> +	    "<div id='header_tree_title'>Tree:</div>"
                                                    ^^
\n is in the corresponding fcgi_gen_response()

> +	    "<div id='header_tree'>%s</div>"
                                           ^^
\n also not here but is in the corresponding fcgi_gen_response()

> +	    "<div class='header_age_title'>Date:</div>\n"
> +	    "<div class='header_age'>%s</div>\n"
> +	    "<div id='header_commit_msg_title'>Message:</div>\n"
> +	    "<div id='header_commit_msg'>%s</div>\n"
> +	    "</div>\n"		/* #tree_header */
> +	    "</div>\n"		/* #tree_header_wrapper */
> +	    "<div class='dotted_line'></div>\n"
> +	    "<div id='tree'>\n",
> +	    rc->tree_id,
> +	    age ? age : "",
> +	    rc->commit_msg);
> +	if (r == -1)
>  		goto done;
> -	if (fcgi_gen_response(c, "<div id='tree_title'>Tree</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
>  
> -	if (fcgi_gen_response(c, "<div id='tree_content'>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div id='tree_header_wrapper'>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='tree_header'>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div id='header_tree_title'>Tree:"
> -	    "</div>\n") == -1)

                   ^^ here

> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='header_tree'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, rc->tree_id) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)

                                        ^^ and here

> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div class='header_age_title'>Date:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div class='header_age'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, age ? age : "") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div id='header_commit_msg_title'>Message:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='header_commit_msg'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, rc->commit_msg) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div class='dotted_line'></div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='tree'>\n") == -1)
> -		goto done;
> -
>  	error = got_output_repo_tree(c);
>  	if (error)
>  		goto done;
>  
> -	fcgi_gen_response(c, "</div>\n");
> -	fcgi_gen_response(c, "</div>\n");
> +	fcgi_printf(c, "</div>\n"); /* #tree */
> +	fcgi_printf(c, "</div>\n"); /* #tre_content */

                                       #tree_content

>  done:
>  	return error;
>  }
> @@ -1970,6 +1506,7 @@ gotweb_render_diff(struct request *c)
>  	struct transport *t = c->t;
>  	struct repo_commit *rc = NULL;
>  	char *age = NULL, *author = NULL;
> +	int r;
>  
>  	error = got_get_repo_commits(c, 1);
>  	if (error)
> @@ -1984,101 +1521,44 @@ gotweb_render_diff(struct request *c)
>  	if (error)
>  		goto done;
>  
> -	if (fcgi_gen_response(c, "<div id='diff_title_wrapper'>\n") == -1)
> +	r = fcgi_printf(c, "<div id='diff_title_wrapper'>\n"
> +	    "<div id='diff_title'>Commit Diff</div>\n"
> +	    "</div>"		/* #diff_title_wrapper */

                   ^^
                   \n not here but is in previous

> +	    "<div id='diff_content'>\n"
> +	    "<div id='diff_header_wrapper'>\n"
> +	    "<div id='diff_header'>\n"
> +	    "<div id='header_diff_title'>Diff:</div>\n"
> +	    "<div id='header_diff'>%s<br />%s</div>\n"
> +	    "<div class='header_commit_title'>Commit:</div>\n"
> +	    "<div class='header_commit'>%s</div>"

                                                ^^ \n

> +	    "<div id='header_tree_title'>Tree:</div>\n"
> +	    "<div id='header_tree'>%s</div>\n"
> +	    "<div class='header_author_title'>Author:</div>\n"
> +	    "<div class='header_author'>%s</div>\n"
> +	    "<div class='header_age_title'>Date:</div>\n"
> +	    "<div class='header_age'>%s</div>"

                                             ^^ \n

> +	    "<div id='header_commit_msg_title'>Message:</div>\n"
> +	    "<div id='header_commit_msg'>%s</div>"

                                                 ^^ \n

> +	    "</div>"		/* #diff_header */

                   ^^ \n

> +	    "</div>"		/* #diff_header_wrapper */

                   ^^ \n

> +	    "<div class='dotted_line'></div>\n"
> +	    "<div id='diff'>\n",
> +	    rc->parent_id, rc->commit_id,
> +	    rc->commit_id,
> +	    rc->tree_id,
> +	    author ? author : "",
> +	    age ? age : "",
> +	    rc->commit_msg);
> +	if (r == -1)
>  		goto done;
> -	if (fcgi_gen_response(c,
> -	    "<div id='diff_title'>Commit Diff</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
>  
> -	if (fcgi_gen_response(c, "<div id='diff_content'>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='diff_header_wrapper'>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='diff_header'>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div id='header_diff_title'>Diff:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='header_diff'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, rc->parent_id) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<br />") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, rc->commit_id) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div class='header_commit_title'>Commit:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div class='header_commit'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, rc->commit_id) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div id='header_tree_title'>Tree:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='header_tree'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, rc->tree_id) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div class='header_author_title'>Author:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div class='header_author'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, author ? author : "") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div class='header_age_title'>Date:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div class='header_age'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, age ? age : "") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div id='header_commit_msg_title'>Message:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='header_commit_msg'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, rc->commit_msg) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div class='dotted_line'></div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='diff'>\n") == -1)
> -		goto done;
> -
>  	error = got_output_repo_diff(c);
>  	if (error)
>  		goto done;
>  
> -	fcgi_gen_response(c, "</div>\n");
> +	fcgi_printf(c, "</div>\n"); /* #diff */
> +	fcgi_printf(c, "</div>\n"); /* #diff_content */

                        ^^^^^^^^ second </div> tag was after done:

>  done:
> -	fcgi_gen_response(c, "</div>\n");

                              ^^^^^^^^ here

>  	free(age);
>  	free(author);
>  	return error;
> @@ -2090,66 +1570,50 @@ gotweb_render_summary(struct request *c)
>  	const struct got_error *error = NULL;
>  	struct transport *t = c->t;
>  	struct server *srv = c->srv;
> +	int r;
>  
> -	if (fcgi_gen_response(c, "<div id='summary_wrapper'>\n") == -1)
> +	if (fcgi_printf(c, "<div id='summary_wrapper'>\n") == -1)
>  		goto done;
>  
> -	if (!srv->show_repo_description)
> -		goto owner;
> +	if (srv->show_repo_description) {
> +		r = fcgi_printf(c,
> +		    "<div id='description_title'>Description:</div>\n"
> +		    "<div id='description'>%s</div>",

                                                   ^^ \n

> +		    t->repo_dir->description);
> +		if (r == -1)
> +			goto done;
> +	}
>  
> -	if (fcgi_gen_response(c, "<div id='description_title'>"
> -	    "Description:</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='description'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, t->repo_dir->description) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -owner:
> -	if (!srv->show_repo_owner)
> -		goto last_change;
> +	if (srv->show_repo_owner) {
> +		r = fcgi_printf(c,
> +		    "<div id='repo_owner_title'>Owner:</div>\n"
> +		    "<div id='repo_owner'>%s</div>",

                                                  ^^ \n

> +		    t->repo_dir->owner);
> +		if (r == -1)
> +			goto done;
> +	}
>  
> -	if (fcgi_gen_response(c, "<div id='repo_owner_title'>"
> -	    "Owner:</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='repo_owner'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, t->repo_dir->owner) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -last_change:
> -	if (!srv->show_repo_age)
> -		goto clone_url;
> +	if (srv->show_repo_age) {
> +		r = fcgi_printf(c,
> +		    "<div id='last_change_title'>Last Change:</div>\n"
> +		    "<div id='last_change'>%s</div>",

                                                   ^^ \n

> +		    t->repo_dir->age);
> +		if (r == -1)
> +			goto done;
> +	}
>  
> -	if (fcgi_gen_response(c, "<div id='last_change_title'>"
> -	    "Last Change:</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='last_change'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, t->repo_dir->age) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -clone_url:
> -	if (!srv->show_repo_cloneurl)
> -		goto content;
> +	if (srv->show_repo_cloneurl) {
> +		r = fcgi_printf(c,
> +		    "<div id='cloneurl_title'>Clone URL:</div>\n"
> +		    "<div id='cloneurl'>%s</div>",

                                                ^^ \n

> +		    t->repo_dir->url ? t->repo_dir->url : "");
> +		if (r == -1)
> +			goto done;
> +	}
>  
> -	if (fcgi_gen_response(c, "<div id='cloneurl_title'>"
> -	    "Clone URL:</div>\n") == -1)
> +	r = fcgi_printf(c, "</div>\n"); /* #summary_wrapper */

                            ^^^^^^ second closing div missing?

> +	if (r == -1)
>  		goto done;
> -	if (fcgi_gen_response(c, "<div id='cloneurl'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, t->repo_dir->url) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -content:
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;

                                  ^^^^^^ there were two
>  
>  	error = gotweb_render_briefs(c);
>  	if (error) {
> @@ -2197,84 +1661,36 @@ gotweb_render_tag(struct request *c)
>  	if (error)
>  		goto done;
>  
> -	if (fcgi_gen_response(c, "<div id='tags_title_wrapper'>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='tags_title'>Tag</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div id='tags_content'>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='tag_header_wrapper'>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='tag_header'>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div class='header_commit_title'>Commit:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div class='header_commit'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, rt->commit_id) == -1)
> -		goto done;
> -
>  	if (strncmp(rt->tag_name, "refs/", 5) == 0)
>  		rt->tag_name += 5;
>  
> -	if (fcgi_gen_response(c, " <span class='refs_str'>(") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, rt->tag_name) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, ")</span>") == -1)
> -		goto done;
> +	fcgi_printf(c, "<div id='tags_title_wrapper'>\n"
> +	    "<div id='tags_title'>Tag</div>\n"
> +	    "</div>\n"		/* #tags_title_wrapper */
> +	    "<div id='tags_content'>\n"
> +	    "<div id='tag_header_wrapper'>\n"
> +	    "<div id='tag_header'>\n"
> +	    "<div class='header_commit_title'>Commit:</div>\n"
> +	    "<div class='header_commit'>%s"
> +	    " <span class='refs_str'>(%s)</span></div>"

                                                      ^^ \n

> +	    "<div class='header_author_title'>Tagger:</div>\n"
> +	    "<div class='header_author'>%s</div>\n"
> +	    "<div class='header_age_title'>Date:</div>\n"
> +	    "<div class='header_age'>%s</div>\n"
> +	    "<div id='header_commit_msg_title'>Message:</div>\n"
> +	    "<div id='header_commit_msg'>%s</div>"

                                                 ^^ \n

> +	    "</div>"		/* #tag_header */

                   ^^ \n

> +	    "<div class='dotted_line'></div>\n"
> +	    "<div id='tag_commit'>\n%s</div>"
> +	    "</div>"		/* tag_header_wrapper */
> +	    ,
> +	    rt->commit_id,
> +	    rt->tag_name,
> +	    author ? author : "",
> +	    age ? age : "",
> +	    rt->commit_msg,
> +	    rt->tag_commit);
>  
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div class='header_author_title'>Tagger:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div class='header_author'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, author ? author : "") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div class='header_age_title'>Date:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div class='header_age'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, age ? age : "") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div id='header_commit_msg_title'>Message:"
> -	    "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='header_commit_msg'>") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, rt->commit_msg) == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "<div class='dotted_line'></div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "<div id='tag_commit'>\n") == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, rt->tag_commit) == -1)
> -		goto done;
> -
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
> -	fcgi_gen_response(c, "</div>\n");
>  done:
>  	free(age);
>  	free(author);
> @@ -2290,10 +1706,13 @@ gotweb_render_tags(struct request *c)
>  	struct transport *t = c->t;
>  	struct querystring *qs = t->qs;
>  	struct repo_dir *repo_dir = t->repo_dir;
> +	const char *index_page_str;
>  	char *newline;
>  	char *age = NULL;
> -	int commit_found = 0;
> +	int r, commit_found = 0;
>  
> +	index_page_str = qs->index_page_str ? qs->index_page_str : "";
> +
>  	if (qs->action == BRIEFS) {
>  		qs->action = TAGS;
>  		error = got_get_repo_tags(c, D_MAXSLCOMMDISP);
> @@ -2302,27 +1721,18 @@ gotweb_render_tags(struct request *c)
>  	if (error)
>  		goto done;
>  
> -	if (fcgi_gen_response(c, "<div id='tags_title_wrapper'>\n") == -1)
> +	r = fcgi_printf(c, "<div id='tags_title_wrapper'>\n"
> +	    "<div id='tags_title'>Tags</div>\n"
> +	    "</div>"		/* #tags_title_wrapper */

                   ^^ \n

> +	    "<div id='tags_content'>\n");
> +	if (r == -1)
>  		goto done;
> -	if (fcgi_gen_response(c,
> -	    "<div id='tags_title'>Tags</div>\n") == -1)
> -		goto done;
> -	if (fcgi_gen_response(c, "</div>\n") == -1)
> -		goto done;
>  
> -	if (fcgi_gen_response(c, "<div id='tags_content'>\n") == -1)
> -		goto done;
> -
>  	if (t->tag_count == 0) {
> -		if (fcgi_gen_response(c, "<div id='err_content'>") == -1)
> +		r = fcgi_printf(c, "<div id='err_content'>%s</div>",

                                                                  ^^ \n

> +		    "This repository contains no tags\n");

second closing div missing after err_content div?

> +		if (r == -1)
>  			goto done;
> -		if (fcgi_gen_response(c,
> -		    "This repository contains no tags\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;

                                          ^^^^^^ two /div
>  	}
>  
>  	TAILQ_FOREACH(rt, &t->repo_tags, entry) {
> @@ -2335,128 +1745,45 @@ gotweb_render_tags(struct request *c)
>  		error = gotweb_get_time_str(&age, rt->tagger_time, TM_DIFF);
>  		if (error)
>  			goto done;
> -		if (fcgi_gen_response(c, "<div class='tag_age'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, age ? age : "") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
>  
> -		if (fcgi_gen_response(c, "<div class='tag'>") == -1)
> -			goto done;
>  		if (strncmp(rt->tag_name, "refs/tags/", 10) == 0)
>  			rt->tag_name += 10;
> -		if (fcgi_gen_response(c, rt->tag_name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
>  
> -		if (fcgi_gen_response(c, "<div class='tag_log'>") == -1)
> -			goto done;
>  		if (rt->tag_commit != NULL) {
>  			newline = strchr(rt->tag_commit, '\n');
>  			if (newline)
>  				*newline = '\0';
>  		}
>  
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> +		r = fcgi_printf(c, "<div class='tag_age'>%s</div>\n"
> +		    "<div class='tag'>%s</div>\n"
> +		    "<div class='tag_log'>"
> +		    "<a href='?index_page=%s&path=%s&action=tag&commit=%s'>"
> +		    "%s</a>"
> +		    "</div>"

                           ^^ \n

> +		    "<div class='navs_wrapper'>\n"
> +		    "<div class='navs'>"
> +		    "<a href='?index_page=%s&path=%s&action=tag&commit=%s'>"
> +		    "tag</a>"
> +		    " | "
> +		    "<a href='?index_page=%s&path=%s&action=briefs&commit=%s'>"
> +		    "commit briefs</a>"
> +		    " | "
> +		    "<a href='?index_page=%s&path=%s&action=commits&commit=%s'>"
> +		    "commits</a>"
> +		    "</div>\n"	/* .navs */
> +		    "</div>\n"	/* .navs_wrapper */
> +		    "<div class='dotted_line'></div>\n",
> +		    age ? age : "",
> +		    rt->tag_name,
> +		    index_page_str, repo_dir->name, rt->commit_id,
> +		    rt->tag_commit ? rt->tag_commit : "",
> +		    index_page_str, repo_dir->name, rt->commit_id,
> +		    index_page_str, repo_dir->name, rt->commit_id,
> +		    index_page_str, repo_dir->name, rt->commit_id);
> +		if (r == -1)
>  			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=tag&commit=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, rt->commit_id) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (rt->tag_commit != NULL &&
> -		    fcgi_gen_response(c, rt->tag_commit) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
>  
> -		if (fcgi_gen_response(c, "<div class='navs_wrapper'>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "<div class='navs'>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=tag&commit=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, rt->commit_id) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "tag") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, " | ") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=briefs&commit=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, rt->commit_id) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "commit briefs") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, " | ") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "<a href='?index_page=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, qs->index_page_str) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&path=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, repo_dir->name) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "&action=commits&commit=") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, rt->commit_id) == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "'>") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "commits") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</a>") == -1)
> -			goto done;
> -
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c, "</div>\n") == -1)
> -			goto done;
> -		if (fcgi_gen_response(c,
> -		    "<div class='dotted_line'></div>\n") == -1)
> -			goto done;
> -
>  		free(age);
>  		age = NULL;
>  	}
> @@ -2465,7 +1792,7 @@ gotweb_render_tags(struct request *c)
>  		if (error)
>  			goto done;
>  	}
> -	fcgi_gen_response(c, "</div>\n");
> +	fcgi_printf(c, "</div>\n"); /* #tags_content */
>  done:
>  	free(age);
>  	return error;
> blob - b58b1e7be0421dac9ff6c9717bacb59208ad1bbb
> file + gotwebd/gotwebd.h
> --- gotwebd/gotwebd.h
> +++ gotwebd/gotwebd.h
> @@ -438,7 +438,9 @@ 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_gen_response(struct request *, const char *);
> +int fcgi_printf(struct request *, const char *, ...)
> +	__attribute__((__format__(printf, 2, 3)))
> +	__attribute__((__nonnull__(2)));
>  int fcgi_gen_binary_response(struct request *, const uint8_t *, int);
>  
>  /* got_operations.c */
> 

-- 
Mark Jamsek <fnc.bsdbox.org>
GPG: F2FF 13DE 6A06 C471 CA80  E6E2 2930 DC66 86EE CF68