diff options
| author | Bryce Kwon <bryce@brycekwon.com> | |
|---|---|---|
| committer | Bryce Kwon <bryce@brycekwon.com> | |
| commit | ||
| parent | ||
| tree | ||
| download | ||
Send a clone file with its size in whole batches
The dumb transport read a pack four kilobytes at a time through stdio
and sent it without a length, so a client could not tell a cut-off
transfer from a complete one.
Diffstat (limited to 'source')
| -rw-r--r-- | source/ui-clone.c | 22 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 file changed, 18 insertions, 4 deletions
diff --git a/source/ui-clone.c b/source/ui-clone.c index 2544e9f..833c170 100644 --- a/source/ui-clone.c +++ b/source/ui-clone.c @@ -95,11 +95,20 @@ static int path_is_safe(const char *path) return 1; } +/* + * The file is read in batches the size of the output buffer, so each one + * goes to the client in a single write, and its size is sent ahead so the + * client can tell a cut-off transfer from a complete one. + */ static void send_file(const char *path) { + static char buf[HTML_BATCH]; struct stat st; + ssize_t got; + int fd; - if (stat(path, &st)) { + fd = open(path, O_RDONLY); + if (fd < 0) { switch (errno) { case ENOENT: cgit_print_error_page(404, "Not Found", "Not found"); @@ -112,8 +121,10 @@ static void send_file(const char *path) } return; } - // fopen opens a directory on most systems and reads nothing from it. - if (!S_ISREG(st.st_mode)) { + // open succeeds on a directory on most systems and reads nothing from + // it. + if (fstat(fd, &st) || !S_ISREG(st.st_mode)) { + close(fd); cgit_print_error_page(404, "Not Found", "Not found"); return; } @@ -123,8 +134,11 @@ static void send_file(const char *path) ctx.page.filename = path; skip_prefix(path, ctx.repo->path, &ctx.page.filename); skip_prefix(ctx.page.filename, "/", &ctx.page.filename); + ctx.page.size = st.st_size; cgit_print_http_headers(); - html_include(path); + while ((got = xread(fd, buf, sizeof(buf))) > 0) + html_raw(buf, got); + close(fd); } void cgit_clone_info(void) |
