Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_autoindex_module.c @ 6077:0395f788b080 stable-1.6
Resolver: fixed use-after-free memory access.
In 954867a2f0a6, we switched to using resolver node as the
timer event data, so make sure we do not free resolver node
memory until the corresponding timer is deleted.
author | Ruslan Ermilov <ru@nginx.com> |
---|---|
date | Thu, 20 Nov 2014 15:24:40 +0300 |
parents | 2cfc095a607a |
children | 631dee7bfd4e |
rev | line source |
---|---|
457 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4412 | 4 * Copyright (C) Nginx, Inc. |
457 | 5 */ |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 #if 0 | |
14 | |
15 typedef struct { | |
16 ngx_buf_t *buf; | |
17 size_t size; | |
18 ngx_pool_t *pool; | |
19 size_t alloc_size; | |
20 ngx_chain_t **last_out; | |
21 } ngx_http_autoindex_ctx_t; | |
22 | |
23 #endif | |
24 | |
25 | |
26 typedef struct { | |
27 ngx_str_t name; | |
525 | 28 size_t utf_len; |
2849
6a62bed048cd
fix colon in file name for ngx_http_autoindex_module
Igor Sysoev <igor@sysoev.ru>
parents:
2721
diff
changeset
|
29 size_t escape; |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
30 size_t escape_html; |
2849
6a62bed048cd
fix colon in file name for ngx_http_autoindex_module
Igor Sysoev <igor@sysoev.ru>
parents:
2721
diff
changeset
|
31 |
6a62bed048cd
fix colon in file name for ngx_http_autoindex_module
Igor Sysoev <igor@sysoev.ru>
parents:
2721
diff
changeset
|
32 unsigned dir:1; |
6a62bed048cd
fix colon in file name for ngx_http_autoindex_module
Igor Sysoev <igor@sysoev.ru>
parents:
2721
diff
changeset
|
33 |
457 | 34 time_t mtime; |
35 off_t size; | |
36 } ngx_http_autoindex_entry_t; | |
37 | |
38 | |
39 typedef struct { | |
40 ngx_flag_t enable; | |
519 | 41 ngx_flag_t localtime; |
527 | 42 ngx_flag_t exact_size; |
457 | 43 } ngx_http_autoindex_loc_conf_t; |
44 | |
45 | |
557 | 46 #define NGX_HTTP_AUTOINDEX_PREALLOCATE 50 |
47 | |
48 #define NGX_HTTP_AUTOINDEX_NAME_LEN 50 | |
457 | 49 |
50 | |
503 | 51 static int ngx_libc_cdecl ngx_http_autoindex_cmp_entries(const void *one, |
52 const void *two); | |
499 | 53 static ngx_int_t ngx_http_autoindex_error(ngx_http_request_t *r, |
557 | 54 ngx_dir_t *dir, ngx_str_t *name); |
681 | 55 static ngx_int_t ngx_http_autoindex_init(ngx_conf_t *cf); |
457 | 56 static void *ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf); |
57 static char *ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf, | |
499 | 58 void *parent, void *child); |
457 | 59 |
60 | |
61 static ngx_command_t ngx_http_autoindex_commands[] = { | |
62 | |
63 { ngx_string("autoindex"), | |
64 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
65 ngx_conf_set_flag_slot, | |
66 NGX_HTTP_LOC_CONF_OFFSET, | |
67 offsetof(ngx_http_autoindex_loc_conf_t, enable), | |
68 NULL }, | |
69 | |
519 | 70 { ngx_string("autoindex_localtime"), |
71 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
72 ngx_conf_set_flag_slot, | |
73 NGX_HTTP_LOC_CONF_OFFSET, | |
74 offsetof(ngx_http_autoindex_loc_conf_t, localtime), | |
75 NULL }, | |
76 | |
527 | 77 { ngx_string("autoindex_exact_size"), |
78 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
79 ngx_conf_set_flag_slot, | |
80 NGX_HTTP_LOC_CONF_OFFSET, | |
81 offsetof(ngx_http_autoindex_loc_conf_t, exact_size), | |
82 NULL }, | |
83 | |
457 | 84 ngx_null_command |
85 }; | |
86 | |
87 | |
667 | 88 static ngx_http_module_t ngx_http_autoindex_module_ctx = { |
509 | 89 NULL, /* preconfiguration */ |
681 | 90 ngx_http_autoindex_init, /* postconfiguration */ |
457 | 91 |
92 NULL, /* create main configuration */ | |
93 NULL, /* init main configuration */ | |
94 | |
95 NULL, /* create server configuration */ | |
96 NULL, /* merge server configuration */ | |
97 | |
4499
778ef9c3fd2d
Fixed spelling in single-line comments.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
98 ngx_http_autoindex_create_loc_conf, /* create location configuration */ |
778ef9c3fd2d
Fixed spelling in single-line comments.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
99 ngx_http_autoindex_merge_loc_conf /* merge location configuration */ |
457 | 100 }; |
101 | |
102 | |
103 ngx_module_t ngx_http_autoindex_module = { | |
509 | 104 NGX_MODULE_V1, |
577 | 105 &ngx_http_autoindex_module_ctx, /* module context */ |
457 | 106 ngx_http_autoindex_commands, /* module directives */ |
107 NGX_HTTP_MODULE, /* module type */ | |
541 | 108 NULL, /* init master */ |
681 | 109 NULL, /* init module */ |
541 | 110 NULL, /* init process */ |
111 NULL, /* init thread */ | |
112 NULL, /* exit thread */ | |
113 NULL, /* exit process */ | |
114 NULL, /* exit master */ | |
115 NGX_MODULE_V1_PADDING | |
457 | 116 }; |
117 | |
118 | |
119 static u_char title[] = | |
120 "<html>" CRLF | |
121 "<head><title>Index of " | |
122 ; | |
123 | |
124 | |
125 static u_char header[] = | |
126 "</title></head>" CRLF | |
127 "<body bgcolor=\"white\">" CRLF | |
128 "<h1>Index of " | |
129 ; | |
130 | |
131 static u_char tail[] = | |
132 "</body>" CRLF | |
133 "</html>" CRLF | |
134 ; | |
135 | |
136 | |
499 | 137 static ngx_int_t |
138 ngx_http_autoindex_handler(ngx_http_request_t *r) | |
457 | 139 { |
557 | 140 u_char *last, *filename, scale; |
527 | 141 off_t length; |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
142 size_t len, char_len, escape_html, allocated, root; |
457 | 143 ngx_tm_t tm; |
144 ngx_err_t err; | |
145 ngx_buf_t *b; | |
557 | 146 ngx_int_t rc, size; |
147 ngx_str_t path; | |
457 | 148 ngx_dir_t dir; |
2889
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
149 ngx_uint_t i, level, utf8; |
457 | 150 ngx_pool_t *pool; |
563 | 151 ngx_time_t *tp; |
557 | 152 ngx_chain_t out; |
457 | 153 ngx_array_t entries; |
154 ngx_http_autoindex_entry_t *entry; | |
155 ngx_http_autoindex_loc_conf_t *alcf; | |
156 | |
157 static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", | |
158 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; | |
159 | |
160 if (r->uri.data[r->uri.len - 1] != '/') { | |
161 return NGX_DECLINED; | |
162 } | |
163 | |
645 | 164 if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { |
637 | 165 return NGX_DECLINED; |
166 } | |
167 | |
457 | 168 alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module); |
169 | |
170 if (!alcf->enable) { | |
171 return NGX_DECLINED; | |
172 } | |
173 | |
557 | 174 /* NGX_DIR_MASK_LEN is lesser than NGX_HTTP_AUTOINDEX_PREALLOCATE */ |
457 | 175 |
773 | 176 last = ngx_http_map_uri_to_path(r, &path, &root, |
177 NGX_HTTP_AUTOINDEX_PREALLOCATE); | |
557 | 178 if (last == NULL) { |
179 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
457 | 180 } |
181 | |
557 | 182 allocated = path.len; |
1627 | 183 path.len = last - path.data; |
184 if (path.len > 1) { | |
185 path.len--; | |
186 } | |
557 | 187 path.data[path.len] = '\0'; |
457 | 188 |
189 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
557 | 190 "http autoindex: \"%s\"", path.data); |
457 | 191 |
557 | 192 if (ngx_open_dir(&path, &dir) == NGX_ERROR) { |
457 | 193 err = ngx_errno; |
194 | |
543 | 195 if (err == NGX_ENOENT |
196 || err == NGX_ENOTDIR | |
197 || err == NGX_ENAMETOOLONG) | |
198 { | |
457 | 199 level = NGX_LOG_ERR; |
200 rc = NGX_HTTP_NOT_FOUND; | |
201 | |
202 } else if (err == NGX_EACCES) { | |
203 level = NGX_LOG_ERR; | |
204 rc = NGX_HTTP_FORBIDDEN; | |
205 | |
206 } else { | |
207 level = NGX_LOG_CRIT; | |
208 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
209 } | |
210 | |
211 ngx_log_error(level, r->connection->log, err, | |
557 | 212 ngx_open_dir_n " \"%s\" failed", path.data); |
457 | 213 |
214 return rc; | |
215 } | |
216 | |
217 #if (NGX_SUPPRESS_WARN) | |
557 | 218 |
457 | 219 /* MSVC thinks 'entries' may be used without having been initialized */ |
220 ngx_memzero(&entries, sizeof(ngx_array_t)); | |
557 | 221 |
457 | 222 #endif |
223 | |
557 | 224 /* TODO: pool should be temporary pool */ |
225 pool = r->pool; | |
226 | |
227 if (ngx_array_init(&entries, pool, 40, sizeof(ngx_http_autoindex_entry_t)) | |
228 != NGX_OK) | |
457 | 229 { |
557 | 230 return ngx_http_autoindex_error(r, &dir, &path); |
457 | 231 } |
232 | |
523 | 233 r->headers_out.status = NGX_HTTP_OK; |
842
d8e2613a2b55
charset could not be set for ngx_http_autoindex_module responses
Igor Sysoev <igor@sysoev.ru>
parents:
773
diff
changeset
|
234 r->headers_out.content_type_len = sizeof("text/html") - 1; |
3516
dd1570b6f237
ngx_str_set() and ngx_str_null()
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
235 ngx_str_set(&r->headers_out.content_type, "text/html"); |
5497
2cfc095a607a
Fixed setting of content type in some cases.
Ruslan Ermilov <ru@nginx.com>
parents:
5333
diff
changeset
|
236 r->headers_out.content_type_lowcase = NULL; |
523 | 237 |
238 rc = ngx_http_send_header(r); | |
239 | |
240 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { | |
1499
090e391f53db
fix file leak for HEAD requests
Igor Sysoev <igor@sysoev.ru>
parents:
842
diff
changeset
|
241 if (ngx_close_dir(&dir) == NGX_ERROR) { |
090e391f53db
fix file leak for HEAD requests
Igor Sysoev <igor@sysoev.ru>
parents:
842
diff
changeset
|
242 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, |
090e391f53db
fix file leak for HEAD requests
Igor Sysoev <igor@sysoev.ru>
parents:
842
diff
changeset
|
243 ngx_close_dir_n " \"%V\" failed", &path); |
090e391f53db
fix file leak for HEAD requests
Igor Sysoev <igor@sysoev.ru>
parents:
842
diff
changeset
|
244 } |
090e391f53db
fix file leak for HEAD requests
Igor Sysoev <igor@sysoev.ru>
parents:
842
diff
changeset
|
245 |
523 | 246 return rc; |
247 } | |
248 | |
557 | 249 filename = path.data; |
250 filename[path.len] = '/'; | |
457 | 251 |
2889
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
252 if (r->headers_out.charset.len == 5 |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
253 && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5) |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
254 == 0) |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
255 { |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
256 utf8 = 1; |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
257 |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
258 } else { |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
259 utf8 = 0; |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
260 } |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
261 |
457 | 262 for ( ;; ) { |
263 ngx_set_errno(0); | |
264 | |
265 if (ngx_read_dir(&dir) == NGX_ERROR) { | |
266 err = ngx_errno; | |
267 | |
501 | 268 if (err != NGX_ENOMOREFILES) { |
457 | 269 ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, |
557 | 270 ngx_read_dir_n " \"%V\" failed", &path); |
271 return ngx_http_autoindex_error(r, &dir, &path); | |
457 | 272 } |
273 | |
577 | 274 break; |
457 | 275 } |
276 | |
277 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
278 "http autoindex file: \"%s\"", ngx_de_name(&dir)); | |
279 | |
280 len = ngx_de_namelen(&dir); | |
281 | |
547 | 282 if (ngx_de_name(&dir)[0] == '.') { |
459 | 283 continue; |
284 } | |
285 | |
457 | 286 if (!dir.valid_info) { |
287 | |
557 | 288 /* 1 byte for '/' and 1 byte for terminating '\0' */ |
457 | 289 |
557 | 290 if (path.len + 1 + len + 1 > allocated) { |
291 allocated = path.len + 1 + len + 1 | |
292 + NGX_HTTP_AUTOINDEX_PREALLOCATE; | |
293 | |
2049 | 294 filename = ngx_pnalloc(pool, allocated); |
557 | 295 if (filename == NULL) { |
296 return ngx_http_autoindex_error(r, &dir, &path); | |
457 | 297 } |
298 | |
557 | 299 last = ngx_cpystrn(filename, path.data, path.len + 1); |
457 | 300 *last++ = '/'; |
301 } | |
302 | |
303 ngx_cpystrn(last, ngx_de_name(&dir), len + 1); | |
304 | |
557 | 305 if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { |
497 | 306 err = ngx_errno; |
307 | |
5333
e8bca8397625
Autoindex: improved ngx_de_info() error handling.
Sergey Kandaurov <pluknet@nginx.com>
parents:
5332
diff
changeset
|
308 if (err != NGX_ENOENT && err != NGX_ELOOP) { |
497 | 309 ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, |
557 | 310 ngx_de_info_n " \"%s\" failed", filename); |
2371
b438ffe54e34
skip protected symlinks in autoindex
Igor Sysoev <igor@sysoev.ru>
parents:
2125
diff
changeset
|
311 |
b438ffe54e34
skip protected symlinks in autoindex
Igor Sysoev <igor@sysoev.ru>
parents:
2125
diff
changeset
|
312 if (err == NGX_EACCES) { |
b438ffe54e34
skip protected symlinks in autoindex
Igor Sysoev <igor@sysoev.ru>
parents:
2125
diff
changeset
|
313 continue; |
b438ffe54e34
skip protected symlinks in autoindex
Igor Sysoev <igor@sysoev.ru>
parents:
2125
diff
changeset
|
314 } |
b438ffe54e34
skip protected symlinks in autoindex
Igor Sysoev <igor@sysoev.ru>
parents:
2125
diff
changeset
|
315 |
557 | 316 return ngx_http_autoindex_error(r, &dir, &path); |
497 | 317 } |
318 | |
557 | 319 if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { |
497 | 320 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, |
321 ngx_de_link_info_n " \"%s\" failed", | |
557 | 322 filename); |
323 return ngx_http_autoindex_error(r, &dir, &path); | |
497 | 324 } |
457 | 325 } |
326 } | |
327 | |
501 | 328 entry = ngx_array_push(&entries); |
329 if (entry == NULL) { | |
557 | 330 return ngx_http_autoindex_error(r, &dir, &path); |
457 | 331 } |
332 | |
577 | 333 entry->name.len = len; |
525 | 334 |
2049 | 335 entry->name.data = ngx_pnalloc(pool, len + 1); |
501 | 336 if (entry->name.data == NULL) { |
557 | 337 return ngx_http_autoindex_error(r, &dir, &path); |
457 | 338 } |
461 | 339 |
457 | 340 ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); |
341 | |
529 | 342 entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len, |
4192
61e4af19df9f
Autoindex: escape '?' in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
3527
diff
changeset
|
343 NGX_ESCAPE_URI_COMPONENT); |
529 | 344 |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
345 entry->escape_html = ngx_escape_html(NULL, entry->name.data, |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
346 entry->name.len); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
347 |
2889
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
348 if (utf8) { |
2125
8e4b9d2acde8
rename ngx_utf_...() to ngx_utf8_...()
Igor Sysoev <igor@sysoev.ru>
parents:
2120
diff
changeset
|
349 entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len); |
525 | 350 } else { |
351 entry->utf_len = len; | |
352 } | |
353 | |
457 | 354 entry->dir = ngx_de_is_dir(&dir); |
355 entry->mtime = ngx_de_mtime(&dir); | |
356 entry->size = ngx_de_size(&dir); | |
357 } | |
358 | |
359 if (ngx_close_dir(&dir) == NGX_ERROR) { | |
360 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, | |
5218 | 361 ngx_close_dir_n " \"%V\" failed", &path); |
457 | 362 } |
363 | |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
364 escape_html = ngx_escape_html(NULL, r->uri.data, r->uri.len); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
365 |
457 | 366 len = sizeof(title) - 1 |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
367 + r->uri.len + escape_html |
457 | 368 + sizeof(header) - 1 |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
369 + r->uri.len + escape_html |
457 | 370 + sizeof("</h1>") - 1 |
371 + sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1 | |
372 + sizeof("</pre><hr>") - 1 | |
373 + sizeof(tail) - 1; | |
374 | |
375 entry = entries.elts; | |
376 for (i = 0; i < entries.nelts; i++) { | |
377 len += sizeof("<a href=\"") - 1 | |
529 | 378 + entry[i].name.len + entry[i].escape |
525 | 379 + 1 /* 1 is for "/" */ |
380 + sizeof("\">") - 1 | |
4192
61e4af19df9f
Autoindex: escape '?' in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
3527
diff
changeset
|
381 + entry[i].name.len - entry[i].utf_len |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
382 + entry[i].escape_html |
525 | 383 + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof(">") - 2 |
384 + sizeof("</a>") - 1 | |
385 + sizeof(" 28-Sep-1970 12:00 ") - 1 | |
529 | 386 + 20 /* the file size */ |
525 | 387 + 2; |
457 | 388 } |
389 | |
501 | 390 b = ngx_create_temp_buf(r->pool, len); |
391 if (b == NULL) { | |
5332
1a9700ef9725
Autoindex: return NGX_ERROR on error if headers were sent.
Sergey Kandaurov <pluknet@nginx.com>
parents:
5218
diff
changeset
|
392 return NGX_ERROR; |
457 | 393 } |
394 | |
395 if (entries.nelts > 1) { | |
396 ngx_qsort(entry, (size_t) entries.nelts, | |
397 sizeof(ngx_http_autoindex_entry_t), | |
398 ngx_http_autoindex_cmp_entries); | |
399 } | |
400 | |
401 b->last = ngx_cpymem(b->last, title, sizeof(title) - 1); | |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
402 |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
403 if (escape_html) { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
404 b->last = (u_char *) ngx_escape_html(b->last, r->uri.data, r->uri.len); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
405 b->last = ngx_cpymem(b->last, header, sizeof(header) - 1); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
406 b->last = (u_char *) ngx_escape_html(b->last, r->uri.data, r->uri.len); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
407 |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
408 } else { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
409 b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
410 b->last = ngx_cpymem(b->last, header, sizeof(header) - 1); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
411 b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
412 } |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
413 |
457 | 414 b->last = ngx_cpymem(b->last, "</h1>", sizeof("</h1>") - 1); |
415 | |
416 b->last = ngx_cpymem(b->last, "<hr><pre><a href=\"../\">../</a>" CRLF, | |
417 sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1); | |
418 | |
563 | 419 tp = ngx_timeofday(); |
420 | |
457 | 421 for (i = 0; i < entries.nelts; i++) { |
422 b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1); | |
461 | 423 |
424 if (entry[i].escape) { | |
425 ngx_escape_uri(b->last, entry[i].name.data, entry[i].name.len, | |
4192
61e4af19df9f
Autoindex: escape '?' in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
3527
diff
changeset
|
426 NGX_ESCAPE_URI_COMPONENT); |
461 | 427 |
428 b->last += entry[i].name.len + entry[i].escape; | |
429 | |
430 } else { | |
431 b->last = ngx_cpymem(b->last, entry[i].name.data, | |
432 entry[i].name.len); | |
433 } | |
457 | 434 |
435 if (entry[i].dir) { | |
436 *b->last++ = '/'; | |
437 } | |
438 | |
439 *b->last++ = '"'; | |
440 *b->last++ = '>'; | |
441 | |
525 | 442 len = entry[i].utf_len; |
457 | 443 |
2120 | 444 if (entry[i].name.len != len) { |
527 | 445 if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
446 char_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3 + 1; |
527 | 447 |
448 } else { | |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
449 char_len = NGX_HTTP_AUTOINDEX_NAME_LEN + 1; |
527 | 450 } |
451 | |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
452 last = b->last; |
2125
8e4b9d2acde8
rename ngx_utf_...() to ngx_utf8_...()
Igor Sysoev <igor@sysoev.ru>
parents:
2120
diff
changeset
|
453 b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data, |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
454 char_len, entry[i].name.len + 1); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
455 |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
456 if (entry[i].escape_html) { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
457 b->last = (u_char *) ngx_escape_html(last, entry[i].name.data, |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
458 b->last - last); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
459 } |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
460 |
527 | 461 last = b->last; |
462 | |
463 } else { | |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
464 if (entry[i].escape_html) { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
465 if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
466 char_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3; |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
467 |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
468 } else { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
469 char_len = len; |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
470 } |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
471 |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
472 b->last = (u_char *) ngx_escape_html(b->last, |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
473 entry[i].name.data, char_len); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
474 last = b->last; |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
475 |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
476 } else { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
477 b->last = ngx_cpystrn(b->last, entry[i].name.data, |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
478 NGX_HTTP_AUTOINDEX_NAME_LEN + 1); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
479 last = b->last - 3; |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
480 } |
527 | 481 } |
482 | |
457 | 483 if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { |
527 | 484 b->last = ngx_cpymem(last, "..></a>", sizeof("..></a>") - 1); |
457 | 485 |
486 } else { | |
487 if (entry[i].dir && NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) { | |
488 *b->last++ = '/'; | |
489 len++; | |
490 } | |
491 | |
492 b->last = ngx_cpymem(b->last, "</a>", sizeof("</a>") - 1); | |
5069
e9d188e295cf
Fixed false memset warning on Linux with -O3 (ticket #275).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4499
diff
changeset
|
493 |
e9d188e295cf
Fixed false memset warning on Linux with -O3 (ticket #275).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4499
diff
changeset
|
494 if (NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) { |
e9d188e295cf
Fixed false memset warning on Linux with -O3 (ticket #275).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4499
diff
changeset
|
495 ngx_memset(b->last, ' ', NGX_HTTP_AUTOINDEX_NAME_LEN - len); |
e9d188e295cf
Fixed false memset warning on Linux with -O3 (ticket #275).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4499
diff
changeset
|
496 b->last += NGX_HTTP_AUTOINDEX_NAME_LEN - len; |
e9d188e295cf
Fixed false memset warning on Linux with -O3 (ticket #275).
Maxim Dounin <mdounin@mdounin.ru>
parents:
4499
diff
changeset
|
497 } |
457 | 498 } |
499 | |
500 *b->last++ = ' '; | |
501 | |
563 | 502 ngx_gmtime(entry[i].mtime + tp->gmtoff * 60 * alcf->localtime, &tm); |
457 | 503 |
504 b->last = ngx_sprintf(b->last, "%02d-%s-%d %02d:%02d ", | |
505 tm.ngx_tm_mday, | |
506 months[tm.ngx_tm_mon - 1], | |
507 tm.ngx_tm_year, | |
508 tm.ngx_tm_hour, | |
509 tm.ngx_tm_min); | |
510 | |
527 | 511 if (alcf->exact_size) { |
512 if (entry[i].dir) { | |
513 b->last = ngx_cpymem(b->last, " -", | |
514 sizeof(" -") - 1); | |
515 } else { | |
516 b->last = ngx_sprintf(b->last, "%19O", entry[i].size); | |
577 | 517 } |
457 | 518 |
519 } else { | |
527 | 520 if (entry[i].dir) { |
547 | 521 b->last = ngx_cpymem(b->last, " -", |
522 sizeof(" -") - 1); | |
527 | 523 |
524 } else { | |
525 length = entry[i].size; | |
526 | |
527 if (length > 1024 * 1024 * 1024 - 1) { | |
528 size = (ngx_int_t) (length / (1024 * 1024 * 1024)); | |
529 if ((length % (1024 * 1024 * 1024)) | |
530 > (1024 * 1024 * 1024 / 2 - 1)) | |
577 | 531 { |
527 | 532 size++; |
533 } | |
534 scale = 'G'; | |
535 | |
536 } else if (length > 1024 * 1024 - 1) { | |
537 size = (ngx_int_t) (length / (1024 * 1024)); | |
538 if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) { | |
539 size++; | |
540 } | |
541 scale = 'M'; | |
542 | |
543 } else if (length > 9999) { | |
544 size = (ngx_int_t) (length / 1024); | |
545 if (length % 1024 > 511) { | |
546 size++; | |
547 } | |
548 scale = 'K'; | |
549 | |
550 } else { | |
551 size = (ngx_int_t) length; | |
547 | 552 scale = '\0'; |
527 | 553 } |
554 | |
547 | 555 if (scale) { |
556 b->last = ngx_sprintf(b->last, "%6i%c", size, scale); | |
527 | 557 |
547 | 558 } else { |
559 b->last = ngx_sprintf(b->last, " %6i", size); | |
527 | 560 } |
561 } | |
457 | 562 } |
563 | |
564 *b->last++ = CR; | |
565 *b->last++ = LF; | |
566 } | |
567 | |
459 | 568 /* TODO: free temporary pool */ |
569 | |
457 | 570 b->last = ngx_cpymem(b->last, "</pre><hr>", sizeof("</pre><hr>") - 1); |
571 | |
572 b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1); | |
573 | |
597 | 574 if (r == r->main) { |
457 | 575 b->last_buf = 1; |
576 } | |
577 | |
509 | 578 b->last_in_chain = 1; |
579 | |
457 | 580 out.buf = b; |
581 out.next = NULL; | |
582 | |
583 return ngx_http_output_filter(r, &out); | |
584 } | |
585 | |
586 | |
503 | 587 static int ngx_libc_cdecl |
499 | 588 ngx_http_autoindex_cmp_entries(const void *one, const void *two) |
457 | 589 { |
590 ngx_http_autoindex_entry_t *first = (ngx_http_autoindex_entry_t *) one; | |
591 ngx_http_autoindex_entry_t *second = (ngx_http_autoindex_entry_t *) two; | |
592 | |
593 if (first->dir && !second->dir) { | |
594 /* move the directories to the start */ | |
595 return -1; | |
596 } | |
597 | |
598 if (!first->dir && second->dir) { | |
599 /* move the directories to the start */ | |
600 return 1; | |
601 } | |
602 | |
603 return (int) ngx_strcmp(first->name.data, second->name.data); | |
604 } | |
605 | |
606 | |
607 #if 0 | |
608 | |
499 | 609 static ngx_buf_t * |
610 ngx_http_autoindex_alloc(ngx_http_autoindex_ctx_t *ctx, size_t size) | |
457 | 611 { |
612 ngx_chain_t *cl; | |
613 | |
614 if (ctx->buf) { | |
615 | |
616 if ((size_t) (ctx->buf->end - ctx->buf->last) >= size) { | |
617 return ctx->buf; | |
618 } | |
619 | |
620 ctx->size += ctx->buf->last - ctx->buf->pos; | |
621 } | |
622 | |
501 | 623 ctx->buf = ngx_create_temp_buf(ctx->pool, ctx->alloc_size); |
624 if (ctx->buf == NULL) { | |
457 | 625 return NULL; |
626 } | |
627 | |
501 | 628 cl = ngx_alloc_chain_link(ctx->pool); |
629 if (cl == NULL) { | |
457 | 630 return NULL; |
631 } | |
632 | |
633 cl->buf = ctx->buf; | |
634 cl->next = NULL; | |
635 | |
636 *ctx->last_out = cl; | |
637 ctx->last_out = &cl->next; | |
638 | |
639 return ctx->buf; | |
640 } | |
641 | |
642 #endif | |
643 | |
644 | |
499 | 645 static ngx_int_t |
557 | 646 ngx_http_autoindex_error(ngx_http_request_t *r, ngx_dir_t *dir, ngx_str_t *name) |
457 | 647 { |
648 if (ngx_close_dir(dir) == NGX_ERROR) { | |
649 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, | |
557 | 650 ngx_close_dir_n " \"%V\" failed", name); |
457 | 651 } |
652 | |
5332
1a9700ef9725
Autoindex: return NGX_ERROR on error if headers were sent.
Sergey Kandaurov <pluknet@nginx.com>
parents:
5218
diff
changeset
|
653 return r->header_sent ? NGX_ERROR : NGX_HTTP_INTERNAL_SERVER_ERROR; |
457 | 654 } |
655 | |
656 | |
499 | 657 static void * |
658 ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf) | |
457 | 659 { |
660 ngx_http_autoindex_loc_conf_t *conf; | |
661 | |
662 conf = ngx_palloc(cf->pool, sizeof(ngx_http_autoindex_loc_conf_t)); | |
663 if (conf == NULL) { | |
2912
c7d57b539248
return NULL instead of NGX_CONF_ERROR on a create conf failure
Igor Sysoev <igor@sysoev.ru>
parents:
2889
diff
changeset
|
664 return NULL; |
457 | 665 } |
666 | |
667 conf->enable = NGX_CONF_UNSET; | |
519 | 668 conf->localtime = NGX_CONF_UNSET; |
527 | 669 conf->exact_size = NGX_CONF_UNSET; |
457 | 670 |
671 return conf; | |
672 } | |
673 | |
674 | |
499 | 675 static char * |
676 ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) | |
457 | 677 { |
678 ngx_http_autoindex_loc_conf_t *prev = parent; | |
679 ngx_http_autoindex_loc_conf_t *conf = child; | |
680 | |
681 ngx_conf_merge_value(conf->enable, prev->enable, 0); | |
519 | 682 ngx_conf_merge_value(conf->localtime, prev->localtime, 0); |
527 | 683 ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1); |
457 | 684 |
685 return NGX_CONF_OK; | |
686 } | |
681 | 687 |
688 | |
689 static ngx_int_t | |
690 ngx_http_autoindex_init(ngx_conf_t *cf) | |
691 { | |
692 ngx_http_handler_pt *h; | |
693 ngx_http_core_main_conf_t *cmcf; | |
694 | |
695 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); | |
696 | |
697 h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); | |
698 if (h == NULL) { | |
699 return NGX_ERROR; | |
700 } | |
701 | |
702 *h = ngx_http_autoindex_handler; | |
703 | |
704 return NGX_OK; | |
705 } |