1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_http.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyev#if 0
14e18a033bSKonstantin Ananyev
15e18a033bSKonstantin Ananyevtypedef struct {
16e18a033bSKonstantin Ananyev    ngx_buf_t     *buf;
17e18a033bSKonstantin Ananyev    size_t         size;
18e18a033bSKonstantin Ananyev    ngx_pool_t    *pool;
19e18a033bSKonstantin Ananyev    size_t         alloc_size;
20e18a033bSKonstantin Ananyev    ngx_chain_t  **last_out;
21e18a033bSKonstantin Ananyev} ngx_http_autoindex_ctx_t;
22e18a033bSKonstantin Ananyev
23e18a033bSKonstantin Ananyev#endif
24e18a033bSKonstantin Ananyev
25e18a033bSKonstantin Ananyev
26e18a033bSKonstantin Ananyevtypedef struct {
27e18a033bSKonstantin Ananyev    ngx_str_t      name;
28e18a033bSKonstantin Ananyev    size_t         utf_len;
29e18a033bSKonstantin Ananyev    size_t         escape;
30e18a033bSKonstantin Ananyev    size_t         escape_html;
31e18a033bSKonstantin Ananyev
32e18a033bSKonstantin Ananyev    unsigned       dir:1;
33e18a033bSKonstantin Ananyev    unsigned       file:1;
34e18a033bSKonstantin Ananyev
35e18a033bSKonstantin Ananyev    time_t         mtime;
36e18a033bSKonstantin Ananyev    off_t          size;
37e18a033bSKonstantin Ananyev} ngx_http_autoindex_entry_t;
38e18a033bSKonstantin Ananyev
39e18a033bSKonstantin Ananyev
40e18a033bSKonstantin Ananyevtypedef struct {
41e18a033bSKonstantin Ananyev    ngx_flag_t     enable;
42e18a033bSKonstantin Ananyev    ngx_uint_t     format;
43e18a033bSKonstantin Ananyev    ngx_flag_t     localtime;
44e18a033bSKonstantin Ananyev    ngx_flag_t     exact_size;
45e18a033bSKonstantin Ananyev} ngx_http_autoindex_loc_conf_t;
46e18a033bSKonstantin Ananyev
47e18a033bSKonstantin Ananyev
48e18a033bSKonstantin Ananyev#define NGX_HTTP_AUTOINDEX_HTML         0
49e18a033bSKonstantin Ananyev#define NGX_HTTP_AUTOINDEX_JSON         1
50e18a033bSKonstantin Ananyev#define NGX_HTTP_AUTOINDEX_JSONP        2
51e18a033bSKonstantin Ananyev#define NGX_HTTP_AUTOINDEX_XML          3
52e18a033bSKonstantin Ananyev
53e18a033bSKonstantin Ananyev#define NGX_HTTP_AUTOINDEX_PREALLOCATE  50
54e18a033bSKonstantin Ananyev
55e18a033bSKonstantin Ananyev#define NGX_HTTP_AUTOINDEX_NAME_LEN     50
56e18a033bSKonstantin Ananyev
57e18a033bSKonstantin Ananyev
58e18a033bSKonstantin Ananyevstatic ngx_buf_t *ngx_http_autoindex_html(ngx_http_request_t *r,
59e18a033bSKonstantin Ananyev    ngx_array_t *entries);
60e18a033bSKonstantin Ananyevstatic ngx_buf_t *ngx_http_autoindex_json(ngx_http_request_t *r,
61e18a033bSKonstantin Ananyev    ngx_array_t *entries, ngx_str_t *callback);
62e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_autoindex_jsonp_callback(ngx_http_request_t *r,
63e18a033bSKonstantin Ananyev    ngx_str_t *callback);
64e18a033bSKonstantin Ananyevstatic ngx_buf_t *ngx_http_autoindex_xml(ngx_http_request_t *r,
65e18a033bSKonstantin Ananyev    ngx_array_t *entries);
66e18a033bSKonstantin Ananyev
67e18a033bSKonstantin Ananyevstatic int ngx_libc_cdecl ngx_http_autoindex_cmp_entries(const void *one,
68e18a033bSKonstantin Ananyev    const void *two);
69e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_autoindex_error(ngx_http_request_t *r,
70e18a033bSKonstantin Ananyev    ngx_dir_t *dir, ngx_str_t *name);
71e18a033bSKonstantin Ananyev
72e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_autoindex_init(ngx_conf_t *cf);
73e18a033bSKonstantin Ananyevstatic void *ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf);
74e18a033bSKonstantin Ananyevstatic char *ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf,
75e18a033bSKonstantin Ananyev    void *parent, void *child);
76e18a033bSKonstantin Ananyev
77e18a033bSKonstantin Ananyev
78e18a033bSKonstantin Ananyevstatic ngx_conf_enum_t  ngx_http_autoindex_format[] = {
79e18a033bSKonstantin Ananyev    { ngx_string("html"), NGX_HTTP_AUTOINDEX_HTML },
80e18a033bSKonstantin Ananyev    { ngx_string("json"), NGX_HTTP_AUTOINDEX_JSON },
81e18a033bSKonstantin Ananyev    { ngx_string("jsonp"), NGX_HTTP_AUTOINDEX_JSONP },
82e18a033bSKonstantin Ananyev    { ngx_string("xml"), NGX_HTTP_AUTOINDEX_XML },
83e18a033bSKonstantin Ananyev    { ngx_null_string, 0 }
84e18a033bSKonstantin Ananyev};
85e18a033bSKonstantin Ananyev
86e18a033bSKonstantin Ananyev
87e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_http_autoindex_commands[] = {
88e18a033bSKonstantin Ananyev
89e18a033bSKonstantin Ananyev    { ngx_string("autoindex"),
90e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
91e18a033bSKonstantin Ananyev      ngx_conf_set_flag_slot,
92e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
93e18a033bSKonstantin Ananyev      offsetof(ngx_http_autoindex_loc_conf_t, enable),
94e18a033bSKonstantin Ananyev      NULL },
95e18a033bSKonstantin Ananyev
96e18a033bSKonstantin Ananyev    { ngx_string("autoindex_format"),
97e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
98e18a033bSKonstantin Ananyev      ngx_conf_set_enum_slot,
99e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
100e18a033bSKonstantin Ananyev      offsetof(ngx_http_autoindex_loc_conf_t, format),
101e18a033bSKonstantin Ananyev      &ngx_http_autoindex_format },
102e18a033bSKonstantin Ananyev
103e18a033bSKonstantin Ananyev    { ngx_string("autoindex_localtime"),
104e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
105e18a033bSKonstantin Ananyev      ngx_conf_set_flag_slot,
106e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
107e18a033bSKonstantin Ananyev      offsetof(ngx_http_autoindex_loc_conf_t, localtime),
108e18a033bSKonstantin Ananyev      NULL },
109e18a033bSKonstantin Ananyev
110e18a033bSKonstantin Ananyev    { ngx_string("autoindex_exact_size"),
111e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
112e18a033bSKonstantin Ananyev      ngx_conf_set_flag_slot,
113e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
114e18a033bSKonstantin Ananyev      offsetof(ngx_http_autoindex_loc_conf_t, exact_size),
115e18a033bSKonstantin Ananyev      NULL },
116e18a033bSKonstantin Ananyev
117e18a033bSKonstantin Ananyev      ngx_null_command
118e18a033bSKonstantin Ananyev};
119e18a033bSKonstantin Ananyev
120e18a033bSKonstantin Ananyev
121e18a033bSKonstantin Ananyevstatic ngx_http_module_t  ngx_http_autoindex_module_ctx = {
122e18a033bSKonstantin Ananyev    NULL,                                  /* preconfiguration */
123e18a033bSKonstantin Ananyev    ngx_http_autoindex_init,               /* postconfiguration */
124e18a033bSKonstantin Ananyev
125e18a033bSKonstantin Ananyev    NULL,                                  /* create main configuration */
126e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
127e18a033bSKonstantin Ananyev
128e18a033bSKonstantin Ananyev    NULL,                                  /* create server configuration */
129e18a033bSKonstantin Ananyev    NULL,                                  /* merge server configuration */
130e18a033bSKonstantin Ananyev
131e18a033bSKonstantin Ananyev    ngx_http_autoindex_create_loc_conf,    /* create location configuration */
132e18a033bSKonstantin Ananyev    ngx_http_autoindex_merge_loc_conf      /* merge location configuration */
133e18a033bSKonstantin Ananyev};
134e18a033bSKonstantin Ananyev
135e18a033bSKonstantin Ananyev
136e18a033bSKonstantin Ananyevngx_module_t  ngx_http_autoindex_module = {
137e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
138e18a033bSKonstantin Ananyev    &ngx_http_autoindex_module_ctx,        /* module context */
139e18a033bSKonstantin Ananyev    ngx_http_autoindex_commands,           /* module directives */
140e18a033bSKonstantin Ananyev    NGX_HTTP_MODULE,                       /* module type */
141e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
142e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
143e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
144e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
145e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
146e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
147e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
148e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
149e18a033bSKonstantin Ananyev};
150e18a033bSKonstantin Ananyev
151e18a033bSKonstantin Ananyev
152e18a033bSKonstantin Ananyevstatic ngx_int_t
153e18a033bSKonstantin Ananyevngx_http_autoindex_handler(ngx_http_request_t *r)
154e18a033bSKonstantin Ananyev{
155e18a033bSKonstantin Ananyev    u_char                         *last, *filename;
156e18a033bSKonstantin Ananyev    size_t                          len, allocated, root;
157e18a033bSKonstantin Ananyev    ngx_err_t                       err;
158e18a033bSKonstantin Ananyev    ngx_buf_t                      *b;
159e18a033bSKonstantin Ananyev    ngx_int_t                       rc;
160e18a033bSKonstantin Ananyev    ngx_str_t                       path, callback;
161e18a033bSKonstantin Ananyev    ngx_dir_t                       dir;
162e18a033bSKonstantin Ananyev    ngx_uint_t                      level, format;
163e18a033bSKonstantin Ananyev    ngx_pool_t                     *pool;
164e18a033bSKonstantin Ananyev    ngx_chain_t                     out;
165e18a033bSKonstantin Ananyev    ngx_array_t                     entries;
166e18a033bSKonstantin Ananyev    ngx_http_autoindex_entry_t     *entry;
167e18a033bSKonstantin Ananyev    ngx_http_autoindex_loc_conf_t  *alcf;
168e18a033bSKonstantin Ananyev
169e18a033bSKonstantin Ananyev    if (r->uri.data[r->uri.len - 1] != '/') {
170e18a033bSKonstantin Ananyev        return NGX_DECLINED;
171e18a033bSKonstantin Ananyev    }
172e18a033bSKonstantin Ananyev
173e18a033bSKonstantin Ananyev    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
174e18a033bSKonstantin Ananyev        return NGX_DECLINED;
175e18a033bSKonstantin Ananyev    }
176e18a033bSKonstantin Ananyev
177e18a033bSKonstantin Ananyev    alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module);
178e18a033bSKonstantin Ananyev
179e18a033bSKonstantin Ananyev    if (!alcf->enable) {
180e18a033bSKonstantin Ananyev        return NGX_DECLINED;
181e18a033bSKonstantin Ananyev    }
182e18a033bSKonstantin Ananyev
183e18a033bSKonstantin Ananyev    /* NGX_DIR_MASK_LEN is lesser than NGX_HTTP_AUTOINDEX_PREALLOCATE */
184e18a033bSKonstantin Ananyev
185e18a033bSKonstantin Ananyev    last = ngx_http_map_uri_to_path(r, &path, &root,
186e18a033bSKonstantin Ananyev                                    NGX_HTTP_AUTOINDEX_PREALLOCATE);
187e18a033bSKonstantin Ananyev    if (last == NULL) {
188e18a033bSKonstantin Ananyev        return NGX_HTTP_INTERNAL_SERVER_ERROR;
189e18a033bSKonstantin Ananyev    }
190e18a033bSKonstantin Ananyev
191e18a033bSKonstantin Ananyev    allocated = path.len;
192e18a033bSKonstantin Ananyev    path.len = last - path.data;
193e18a033bSKonstantin Ananyev    if (path.len > 1) {
194e18a033bSKonstantin Ananyev        path.len--;
195e18a033bSKonstantin Ananyev    }
196e18a033bSKonstantin Ananyev    path.data[path.len] = '\0';
197e18a033bSKonstantin Ananyev
198e18a033bSKonstantin Ananyev    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
199e18a033bSKonstantin Ananyev                   "http autoindex: \"%s\"", path.data);
200e18a033bSKonstantin Ananyev
201e18a033bSKonstantin Ananyev    format = alcf->format;
202e18a033bSKonstantin Ananyev
203e18a033bSKonstantin Ananyev    if (format == NGX_HTTP_AUTOINDEX_JSONP) {
204e18a033bSKonstantin Ananyev        if (ngx_http_autoindex_jsonp_callback(r, &callback) != NGX_OK) {
205e18a033bSKonstantin Ananyev            return NGX_HTTP_BAD_REQUEST;
206e18a033bSKonstantin Ananyev        }
207e18a033bSKonstantin Ananyev
208e18a033bSKonstantin Ananyev        if (callback.len == 0) {
209e18a033bSKonstantin Ananyev            format = NGX_HTTP_AUTOINDEX_JSON;
210e18a033bSKonstantin Ananyev        }
211e18a033bSKonstantin Ananyev    }
212e18a033bSKonstantin Ananyev
213e18a033bSKonstantin Ananyev    if (ngx_open_dir(&path, &dir) == NGX_ERROR) {
214e18a033bSKonstantin Ananyev        err = ngx_errno;
215e18a033bSKonstantin Ananyev
216e18a033bSKonstantin Ananyev        if (err == NGX_ENOENT
217e18a033bSKonstantin Ananyev            || err == NGX_ENOTDIR
218e18a033bSKonstantin Ananyev            || err == NGX_ENAMETOOLONG)
219e18a033bSKonstantin Ananyev        {
220e18a033bSKonstantin Ananyev            level = NGX_LOG_ERR;
221e18a033bSKonstantin Ananyev            rc = NGX_HTTP_NOT_FOUND;
222e18a033bSKonstantin Ananyev
223e18a033bSKonstantin Ananyev        } else if (err == NGX_EACCES) {
224e18a033bSKonstantin Ananyev            level = NGX_LOG_ERR;
225e18a033bSKonstantin Ananyev            rc = NGX_HTTP_FORBIDDEN;
226e18a033bSKonstantin Ananyev
227e18a033bSKonstantin Ananyev        } else {
228e18a033bSKonstantin Ananyev            level = NGX_LOG_CRIT;
229e18a033bSKonstantin Ananyev            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
230e18a033bSKonstantin Ananyev        }
231e18a033bSKonstantin Ananyev
232e18a033bSKonstantin Ananyev        ngx_log_error(level, r->connection->log, err,
233e18a033bSKonstantin Ananyev                      ngx_open_dir_n " \"%s\" failed", path.data);
234e18a033bSKonstantin Ananyev
235e18a033bSKonstantin Ananyev        return rc;
236e18a033bSKonstantin Ananyev    }
237e18a033bSKonstantin Ananyev
238e18a033bSKonstantin Ananyev#if (NGX_SUPPRESS_WARN)
239e18a033bSKonstantin Ananyev
240e18a033bSKonstantin Ananyev    /* MSVC thinks 'entries' may be used without having been initialized */
241e18a033bSKonstantin Ananyev    ngx_memzero(&entries, sizeof(ngx_array_t));
242e18a033bSKonstantin Ananyev
243e18a033bSKonstantin Ananyev#endif
244e18a033bSKonstantin Ananyev
245e18a033bSKonstantin Ananyev    /* TODO: pool should be temporary pool */
246e18a033bSKonstantin Ananyev    pool = r->pool;
247e18a033bSKonstantin Ananyev
248e18a033bSKonstantin Ananyev    if (ngx_array_init(&entries, pool, 40, sizeof(ngx_http_autoindex_entry_t))
249e18a033bSKonstantin Ananyev        != NGX_OK)
250e18a033bSKonstantin Ananyev    {
251e18a033bSKonstantin Ananyev        return ngx_http_autoindex_error(r, &dir, &path);
252e18a033bSKonstantin Ananyev    }
253e18a033bSKonstantin Ananyev
254e18a033bSKonstantin Ananyev    r->headers_out.status = NGX_HTTP_OK;
255e18a033bSKonstantin Ananyev
256e18a033bSKonstantin Ananyev    switch (format) {
257e18a033bSKonstantin Ananyev
258e18a033bSKonstantin Ananyev    case NGX_HTTP_AUTOINDEX_JSON:
259e18a033bSKonstantin Ananyev        ngx_str_set(&r->headers_out.content_type, "application/json");
260e18a033bSKonstantin Ananyev        break;
261e18a033bSKonstantin Ananyev
262e18a033bSKonstantin Ananyev    case NGX_HTTP_AUTOINDEX_JSONP:
263e18a033bSKonstantin Ananyev        ngx_str_set(&r->headers_out.content_type, "application/javascript");
264e18a033bSKonstantin Ananyev        break;
265e18a033bSKonstantin Ananyev
266e18a033bSKonstantin Ananyev    case NGX_HTTP_AUTOINDEX_XML:
267e18a033bSKonstantin Ananyev        ngx_str_set(&r->headers_out.content_type, "text/xml");
268e18a033bSKonstantin Ananyev        ngx_str_set(&r->headers_out.charset, "utf-8");
269e18a033bSKonstantin Ananyev        break;
270e18a033bSKonstantin Ananyev
271e18a033bSKonstantin Ananyev    default: /* NGX_HTTP_AUTOINDEX_HTML */
272e18a033bSKonstantin Ananyev        ngx_str_set(&r->headers_out.content_type, "text/html");
273e18a033bSKonstantin Ananyev        break;
274e18a033bSKonstantin Ananyev    }
275e18a033bSKonstantin Ananyev
276e18a033bSKonstantin Ananyev    r->headers_out.content_type_len = r->headers_out.content_type.len;
277e18a033bSKonstantin Ananyev    r->headers_out.content_type_lowcase = NULL;
278e18a033bSKonstantin Ananyev
279e18a033bSKonstantin Ananyev    rc = ngx_http_send_header(r);
280e18a033bSKonstantin Ananyev
281e18a033bSKonstantin Ananyev    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
282e18a033bSKonstantin Ananyev        if (ngx_close_dir(&dir) == NGX_ERROR) {
283e18a033bSKonstantin Ananyev            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
284e18a033bSKonstantin Ananyev                          ngx_close_dir_n " \"%V\" failed", &path);
285e18a033bSKonstantin Ananyev        }
286e18a033bSKonstantin Ananyev
287e18a033bSKonstantin Ananyev        return rc;
288e18a033bSKonstantin Ananyev    }
289e18a033bSKonstantin Ananyev
290e18a033bSKonstantin Ananyev    filename = path.data;
291e18a033bSKonstantin Ananyev    filename[path.len] = '/';
292e18a033bSKonstantin Ananyev
293e18a033bSKonstantin Ananyev    for ( ;; ) {
294e18a033bSKonstantin Ananyev        ngx_set_errno(0);
295e18a033bSKonstantin Ananyev
296e18a033bSKonstantin Ananyev        if (ngx_read_dir(&dir) == NGX_ERROR) {
297e18a033bSKonstantin Ananyev            err = ngx_errno;
298e18a033bSKonstantin Ananyev
299e18a033bSKonstantin Ananyev            if (err != NGX_ENOMOREFILES) {
300e18a033bSKonstantin Ananyev                ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
301e18a033bSKonstantin Ananyev                              ngx_read_dir_n " \"%V\" failed", &path);
302e18a033bSKonstantin Ananyev                return ngx_http_autoindex_error(r, &dir, &path);
303e18a033bSKonstantin Ananyev            }
304e18a033bSKonstantin Ananyev
305e18a033bSKonstantin Ananyev            break;
306e18a033bSKonstantin Ananyev        }
307e18a033bSKonstantin Ananyev
308e18a033bSKonstantin Ananyev        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
309e18a033bSKonstantin Ananyev                       "http autoindex file: \"%s\"", ngx_de_name(&dir));
310e18a033bSKonstantin Ananyev
311e18a033bSKonstantin Ananyev        len = ngx_de_namelen(&dir);
312e18a033bSKonstantin Ananyev
313e18a033bSKonstantin Ananyev        if (ngx_de_name(&dir)[0] == '.') {
314e18a033bSKonstantin Ananyev            continue;
315e18a033bSKonstantin Ananyev        }
316e18a033bSKonstantin Ananyev
317e18a033bSKonstantin Ananyev        if (!dir.valid_info) {
318e18a033bSKonstantin Ananyev
319e18a033bSKonstantin Ananyev            /* 1 byte for '/' and 1 byte for terminating '\0' */
320e18a033bSKonstantin Ananyev
321e18a033bSKonstantin Ananyev            if (path.len + 1 + len + 1 > allocated) {
322e18a033bSKonstantin Ananyev                allocated = path.len + 1 + len + 1
323e18a033bSKonstantin Ananyev                                     + NGX_HTTP_AUTOINDEX_PREALLOCATE;
324e18a033bSKonstantin Ananyev
325e18a033bSKonstantin Ananyev                filename = ngx_pnalloc(pool, allocated);
326e18a033bSKonstantin Ananyev                if (filename == NULL) {
327e18a033bSKonstantin Ananyev                    return ngx_http_autoindex_error(r, &dir, &path);
328e18a033bSKonstantin Ananyev                }
329e18a033bSKonstantin Ananyev
330e18a033bSKonstantin Ananyev                last = ngx_cpystrn(filename, path.data, path.len + 1);
331e18a033bSKonstantin Ananyev                *last++ = '/';
332e18a033bSKonstantin Ananyev            }
333e18a033bSKonstantin Ananyev
334e18a033bSKonstantin Ananyev            ngx_cpystrn(last, ngx_de_name(&dir), len + 1);
335e18a033bSKonstantin Ananyev
336e18a033bSKonstantin Ananyev            if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) {
337e18a033bSKonstantin Ananyev                err = ngx_errno;
338e18a033bSKonstantin Ananyev
339e18a033bSKonstantin Ananyev                if (err != NGX_ENOENT && err != NGX_ELOOP) {
340e18a033bSKonstantin Ananyev                    ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
341e18a033bSKonstantin Ananyev                                  ngx_de_info_n " \"%s\" failed", filename);
342e18a033bSKonstantin Ananyev
343e18a033bSKonstantin Ananyev                    if (err == NGX_EACCES) {
344e18a033bSKonstantin Ananyev                        continue;
345e18a033bSKonstantin Ananyev                    }
346e18a033bSKonstantin Ananyev
347e18a033bSKonstantin Ananyev                    return ngx_http_autoindex_error(r, &dir, &path);
348e18a033bSKonstantin Ananyev                }
349e18a033bSKonstantin Ananyev
350e18a033bSKonstantin Ananyev                if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) {
351e18a033bSKonstantin Ananyev                    ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
352e18a033bSKonstantin Ananyev                                  ngx_de_link_info_n " \"%s\" failed",
353e18a033bSKonstantin Ananyev                                  filename);
354e18a033bSKonstantin Ananyev                    return ngx_http_autoindex_error(r, &dir, &path);
355e18a033bSKonstantin Ananyev                }
356e18a033bSKonstantin Ananyev            }
357e18a033bSKonstantin Ananyev        }
358e18a033bSKonstantin Ananyev
359e18a033bSKonstantin Ananyev        entry = ngx_array_push(&entries);
360e18a033bSKonstantin Ananyev        if (entry == NULL) {
361e18a033bSKonstantin Ananyev            return ngx_http_autoindex_error(r, &dir, &path);
362e18a033bSKonstantin Ananyev        }
363e18a033bSKonstantin Ananyev
364e18a033bSKonstantin Ananyev        entry->name.len = len;
365e18a033bSKonstantin Ananyev
366e18a033bSKonstantin Ananyev        entry->name.data = ngx_pnalloc(pool, len + 1);
367e18a033bSKonstantin Ananyev        if (entry->name.data == NULL) {
368e18a033bSKonstantin Ananyev            return ngx_http_autoindex_error(r, &dir, &path);
369e18a033bSKonstantin Ananyev        }
370e18a033bSKonstantin Ananyev
371e18a033bSKonstantin Ananyev        ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1);
372e18a033bSKonstantin Ananyev
373e18a033bSKonstantin Ananyev        entry->dir = ngx_de_is_dir(&dir);
374e18a033bSKonstantin Ananyev        entry->file = ngx_de_is_file(&dir);
375e18a033bSKonstantin Ananyev        entry->mtime = ngx_de_mtime(&dir);
376e18a033bSKonstantin Ananyev        entry->size = ngx_de_size(&dir);
377e18a033bSKonstantin Ananyev    }
378e18a033bSKonstantin Ananyev
379e18a033bSKonstantin Ananyev    if (ngx_close_dir(&dir) == NGX_ERROR) {
380e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
381e18a033bSKonstantin Ananyev                      ngx_close_dir_n " \"%V\" failed", &path);
382e18a033bSKonstantin Ananyev    }
383e18a033bSKonstantin Ananyev
384e18a033bSKonstantin Ananyev    if (entries.nelts > 1) {
385e18a033bSKonstantin Ananyev        ngx_qsort(entries.elts, (size_t) entries.nelts,
386e18a033bSKonstantin Ananyev                  sizeof(ngx_http_autoindex_entry_t),
387e18a033bSKonstantin Ananyev                  ngx_http_autoindex_cmp_entries);
388e18a033bSKonstantin Ananyev    }
389e18a033bSKonstantin Ananyev
390e18a033bSKonstantin Ananyev    switch (format) {
391e18a033bSKonstantin Ananyev
392e18a033bSKonstantin Ananyev    case NGX_HTTP_AUTOINDEX_JSON:
393e18a033bSKonstantin Ananyev        b = ngx_http_autoindex_json(r, &entries, NULL);
394e18a033bSKonstantin Ananyev        break;
395e18a033bSKonstantin Ananyev
396e18a033bSKonstantin Ananyev    case NGX_HTTP_AUTOINDEX_JSONP:
397e18a033bSKonstantin Ananyev        b = ngx_http_autoindex_json(r, &entries, &callback);
398e18a033bSKonstantin Ananyev        break;
399e18a033bSKonstantin Ananyev
400e18a033bSKonstantin Ananyev    case NGX_HTTP_AUTOINDEX_XML:
401e18a033bSKonstantin Ananyev        b = ngx_http_autoindex_xml(r, &entries);
402e18a033bSKonstantin Ananyev        break;
403e18a033bSKonstantin Ananyev
404e18a033bSKonstantin Ananyev    default: /* NGX_HTTP_AUTOINDEX_HTML */
405e18a033bSKonstantin Ananyev        b = ngx_http_autoindex_html(r, &entries);
406e18a033bSKonstantin Ananyev        break;
407e18a033bSKonstantin Ananyev    }
408e18a033bSKonstantin Ananyev
409e18a033bSKonstantin Ananyev    if (b == NULL) {
410e18a033bSKonstantin Ananyev        return NGX_ERROR;
411e18a033bSKonstantin Ananyev    }
412e18a033bSKonstantin Ananyev
413e18a033bSKonstantin Ananyev    /* TODO: free temporary pool */
414e18a033bSKonstantin Ananyev
415e18a033bSKonstantin Ananyev    if (r == r->main) {
416