diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/cache.c3
-rw-r--r--source/cgit.c4
-rw-r--r--source/filter.c5
-rw-r--r--source/filter.h6
-rw-r--r--source/html.c20
5 files changed, 34 insertions, 4 deletions
diff --git a/source/cache.c b/source/cache.c
index 8c81f5c..62bb623 100644
--- a/source/cache.c
+++ b/source/cache.c
@@ -175,7 +175,8 @@ static int serve_slot(struct cache_slot *slot)
int err;
err = print_slot(slot);
- if (err)
+ // A client that went away mid-page is not trouble worth a line.
+ if (err && err != EPIPE)
log_error("[cgit] Unable to send slot %s: %s (%d)\n", slot->path, strerror(err), err);
return err;
}
diff --git a/source/cgit.c b/source/cgit.c
index 3e47dbe..633b011 100644
--- a/source/cgit.c
+++ b/source/cgit.c
@@ -1380,7 +1380,9 @@ int cmd_main(int argc, const char **argv)
strbuf_release(&cache_key);
cgit_cleanup_filters();
- if (err)
+ // A slot that could not be sent because the client went away is not
+ // worth an error page nobody will read.
+ if (err && err != EPIPE)
cgit_print_error("Error processing page: %s (%d)", strerror(err), err);
return err;
}
diff --git a/source/filter.c b/source/filter.c
index dd1eaf0..6e16537 100644
--- a/source/filter.c
+++ b/source/filter.c
@@ -450,6 +450,11 @@ void cgit_abort_filters(void)
#endif
}
+int cgit_filter_holds_stdout(void)
+{
+ return running_exec != NULL;
+}
+
static const struct {
const char *prefix;
struct cgit_filter *(*create)(const char *cmd, int argument_count);
diff --git a/source/filter.h b/source/filter.h
index b5a478f..70fa4ff 100644
--- a/source/filter.h
+++ b/source/filter.h
@@ -59,4 +59,10 @@ extern void cgit_cleanup_filters(void);
*/
extern void cgit_abort_filters(void);
+/*
+ * Whether an exec filter holds stdout at the moment, which is when a failed
+ * write means the filter went away rather than the client.
+ */
+extern int cgit_filter_holds_stdout(void);
+
#endif // CGIT_FILTER_H
diff --git a/source/html.c b/source/html.c
index 96b1b52..caa5a29 100644
--- a/source/html.c
+++ b/source/html.c
@@ -10,6 +10,7 @@
#include "cgit.h"
#include "cache.h"
+#include "filter.h"
#include "html.h"
#define HTML_WRITE_BUFSIZE (64 * 1024)
@@ -57,6 +58,8 @@ static struct strbuf *capture;
static void write_out(const char *data, size_t size)
{
+ int err;
+
// A blob or snapshot is well past what one write can move onto a
// pipe, so short writes are resumed rather than reported.
while (size) {
@@ -69,12 +72,25 @@ static void write_out(const char *data, size_t size)
}
if (!size)
return;
+ err = errno;
// While a cache slot is being filled stdout is a file, and a full disk
// must not cost the visitor the page. Abandoning the fill puts stdout
// back on the client along with what the file already holds, so only
// the rest is written again.
- if (!cache_abandon_fill() || write_in_full(STDOUT_FILENO, data, size) < 0)
- die_errno("Unable to write the page");
+ if (cache_abandon_fill()) {
+ if (write_in_full(STDOUT_FILENO, data, size) < 0)
+ die_errno("Unable to write the page");
+ return;
+ }
+ // A client that has gone away fails the write with EPIPE and leaves
+ // nobody to read an error page, so the request ends quietly. A filter
+ // that exited early fails it the same way, and that page has a reader.
+ if (err == EPIPE && !cgit_filter_holds_stdout()) {
+ html_discard();
+ exit(0);
+ }
+ errno = err;
+ die_errno("Unable to write the page");
}
/*