diff options
| author | Bryce Kwon <bryce@brycekwon.com> | |
|---|---|---|
| committer | Bryce Kwon <bryce@brycekwon.com> | |
| commit | ||
| parent | ||
| tree | ||
| download | ||
Gather page output into one buffer
Diffstat (limited to '')
| -rw-r--r-- | source/html.c | 47 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 file changed, 45 insertions, 2 deletions
diff --git a/source/html.c b/source/html.c index c3ab696..dbb0a57 100644 --- a/source/html.c +++ b/source/html.c @@ -9,6 +9,9 @@ #include "cgit.h" #include "html.h" #include "url.h" +#define HTML_WRITE_BUFSIZE (64 * 1024) +static char html_buf[HTML_WRITE_BUFSIZE]; +static size_t html_buflen; /* Percent-encoding of each character, except: a-zA-Z0-9!$()*,./:;@- */ static const char* url_escape_table[256] = { @@ -78,12 +81,52 @@ char *cgit_fmtalloc(const char *format, ...) return strbuf_detach(&sb, NULL); } -void html_raw(const char *data, size_t size) +/* + * Page output is collected here and written out in whole buffers. A page is + * built from a great many small fragments, and writing each one cost a syscall + * apiece: a tree listing spent more time entering the kernel than generating + * anything. + * + * cgit does not own stdout by itself, so the buffer has to be emptied before + * anything else writes there. Those points are a filter taking over stdout, + * the header block that precedes output produced by git itself, the cache + * slot being measured, and process exit. + */ +static void html_write(const char *data, size_t size) { - if (write(STDOUT_FILENO, data, size) != size) + // A blob, snapshot or patch reaches this with a size well past what one + // write can move onto a pipe, so a short write is ordinary rather than + // an error and has to be resumed instead of reported. + if (write_in_full(STDOUT_FILENO, data, size) < 0) die_errno("write error on html output"); } +void html_flush(void) +{ + size_t len = html_buflen; + + if (!len) + return; + // Clear the length first: html_write can die, and the error page it + // produces would otherwise try to flush the same bytes again. + html_buflen = 0; + html_write(html_buf, len); +} + +void html_raw(const char *data, size_t size) +{ + if (size >= HTML_WRITE_BUFSIZE) { + // Nothing is gained by copying a blob through the buffer. + html_flush(); + html_write(data, size); + return; + } + if (html_buflen + size > HTML_WRITE_BUFSIZE) + html_flush(); + memcpy(html_buf + html_buflen, data, size); + html_buflen += size; +} + void html(const char *txt) { html_raw(txt, strlen(txt)); |
