From 8d4da3392c14a3cd171537a37c096570f2143744 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Fri, 26 Mar 2021 22:56:46 -0400 Subject: [mod_dirlisting] read dir in pieces; less blocking read dir in pieces, allowing server to do other work between reads (avoid potentially blocking other requests for long periods of time while reading a large directory) --- src/mod_dirlisting.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src/mod_dirlisting.c') diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c index 8becfc7d..626da4dd 100644 --- a/src/mod_dirlisting.c +++ b/src/mod_dirlisting.c @@ -16,6 +16,7 @@ #include "base.h" #include "log.h" #include "buffer.h" +#include "connections.h"/* joblist_append() */ #include "fdevent.h" #include "http_chunk.h" #include "http_header.h" @@ -102,6 +103,8 @@ typedef struct { plugin_config conf; } handler_ctx; +#define DIRLIST_BATCH 32 + static handler_ctx * mod_dirlisting_handler_ctx_init (plugin_data * const p) { handler_ctx *hctx = calloc(1, sizeof(*hctx)); @@ -916,7 +919,8 @@ static int http_read_directory(handler_ctx * const p) { const int hide_dotfiles = p->conf.hide_dot_files; const uint32_t name_max = p->name_max; struct stat st; - while ((dent = readdir(p->dp)) != NULL) { + int count = -1; + while (++count < DIRLIST_BATCH && (dent = readdir(p->dp)) != NULL) { const char * const d_name = dent->d_name; const uint32_t dsz = (uint32_t) _D_EXACT_NAMLEN(dent); if (d_name[0] == '.') { @@ -978,6 +982,8 @@ static int http_read_directory(handler_ctx * const p) { tmp->namelen = dsz; memcpy(DIRLIST_ENT_NAME(tmp), d_name, dsz + 1); } + if (count == DIRLIST_BATCH) + return HANDLER_WAIT_FOR_EVENT; closedir(p->dp); p->dp = NULL; @@ -994,10 +1000,6 @@ static void http_list_directory(request_st * const r, handler_ctx * const hctx) char sizebuf[sizeof("999.9K")]; struct tm tm; - /* Note: a very large directory may cause lighttpd to pause handling other - * requests while lighttpd processes directory, especially if directory is - * on a remote filesystem */ - /* generate large directory listings into tempfiles * (estimate approx 200-256 bytes of HTML per item; could be up to ~512) */ chunkqueue * const cq = &r->write_queue; @@ -1174,6 +1176,9 @@ SUBREQUEST_FUNC(mod_dirlisting_subrequest) { mod_dirlisting_response(r, hctx); mod_dirlisting_reset(r, p); /*(release resources, including hctx)*/ break; + case HANDLER_WAIT_FOR_EVENT: /*(used here to mean 'yield')*/ + joblist_append(r->con); + break; default: break; } -- cgit v1.2.1