diff options
context:
space:
mode:
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Gather page output into one buffer
Diffstat (limited to '')
-rw-r--r--source/html.c47
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));