autoindex: use temporary pool for directory entries

Directory listing entries (file names, metadata) were previously
allocated into the request pool and lived until request teardown.
Use a temporary pool instead, destroying it immediately after the
response buffer is built.

This frees all entry data on the happy path without waiting for
the request to finish.

All error paths (pool creation failure, header send failure,
read_dir errors, allocation failures, and response build failure)
now destroy the pool before returning.

ngx_http_autoindex_error() accepts an optional pool argument and
destroys it when non-NULL.
This commit is contained in:
srujan-rai 2026-05-04 17:02:43 +05:30
parent 35510ddc94
commit 9a5ded845d

View file

@ -67,7 +67,7 @@ static ngx_buf_t *ngx_http_autoindex_xml(ngx_http_request_t *r,
static int ngx_libc_cdecl ngx_http_autoindex_cmp_entries(const void *one,
const void *two);
static ngx_int_t ngx_http_autoindex_error(ngx_http_request_t *r,
ngx_dir_t *dir, ngx_str_t *name);
ngx_dir_t *dir, ngx_str_t *name, ngx_pool_t *pool);
static ngx_int_t ngx_http_autoindex_init(ngx_conf_t *cf);
static void *ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf);
@ -246,13 +246,15 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
#endif
/* TODO: pool should be temporary pool */
pool = r->pool;
pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, r->connection->log);
if (pool == NULL) {
return ngx_http_autoindex_error(r, &dir, &path, NULL);
}
if (ngx_array_init(&entries, pool, 40, sizeof(ngx_http_autoindex_entry_t))
!= NGX_OK)
{
return ngx_http_autoindex_error(r, &dir, &path);
return ngx_http_autoindex_error(r, &dir, &path, pool);
}
r->headers_out.status = NGX_HTTP_OK;
@ -283,6 +285,8 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
ngx_destroy_pool(pool);
if (ngx_close_dir(&dir) == NGX_ERROR) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
ngx_close_dir_n " \"%V\" failed", &path);
@ -303,7 +307,7 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
if (err != NGX_ENOMOREFILES) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
ngx_read_dir_n " \"%V\" failed", &path);
return ngx_http_autoindex_error(r, &dir, &path);
return ngx_http_autoindex_error(r, &dir, &path, pool);
}
break;
@ -328,7 +332,7 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
filename = ngx_pnalloc(pool, allocated);
if (filename == NULL) {
return ngx_http_autoindex_error(r, &dir, &path);
return ngx_http_autoindex_error(r, &dir, &path, pool);
}
last = ngx_cpystrn(filename, path.data, path.len + 1);
@ -348,28 +352,28 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
continue;
}
return ngx_http_autoindex_error(r, &dir, &path);
return ngx_http_autoindex_error(r, &dir, &path, pool);
}
if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
ngx_de_link_info_n " \"%s\" failed",
filename);
return ngx_http_autoindex_error(r, &dir, &path);
return ngx_http_autoindex_error(r, &dir, &path, pool);
}
}
}
entry = ngx_array_push(&entries);
if (entry == NULL) {
return ngx_http_autoindex_error(r, &dir, &path);
return ngx_http_autoindex_error(r, &dir, &path, pool);
}
entry->name.len = len;
entry->name.data = ngx_pnalloc(pool, len + 1);
if (entry->name.data == NULL) {
return ngx_http_autoindex_error(r, &dir, &path);
return ngx_http_autoindex_error(r, &dir, &path, pool);
}
ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1);
@ -411,10 +415,11 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
}
if (b == NULL) {
ngx_destroy_pool(pool);
return NGX_ERROR;
}
/* TODO: free temporary pool */
ngx_destroy_pool(pool);
if (r == r->main) {
b->last_buf = 1;
@ -1007,8 +1012,13 @@ ngx_http_autoindex_alloc(ngx_http_autoindex_ctx_t *ctx, size_t size)
static ngx_int_t
ngx_http_autoindex_error(ngx_http_request_t *r, ngx_dir_t *dir, ngx_str_t *name)
ngx_http_autoindex_error(ngx_http_request_t *r, ngx_dir_t *dir,
ngx_str_t *name, ngx_pool_t *pool)
{
if (pool != NULL) {
ngx_destroy_pool(pool);
}
if (ngx_close_dir(dir) == NGX_ERROR) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
ngx_close_dir_n " \"%V\" failed", name);