Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_autoindex_module.c @ 4904:c3b276283e4a stable-1.2
Merge of r4885: ssl_verify_client optional_no_ca.
SSL: the "ssl_verify_client" directive parameter "optional_no_ca".
This parameter allows to don't require certificate to be signed by
a trusted CA, e.g. if CA certificate isn't known in advance, like in
WebID protocol.
Note that it doesn't add any security unless the certificate is actually
checked to be trusted by some external means (e.g. by a backend).
Patch by Mike Kazantsev, Eric O'Connor.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Tue, 13 Nov 2012 10:42:16 +0000 |
parents | 778ef9c3fd2d |
children | e9d188e295cf |
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"); |
523 | 236 |
237 rc = ngx_http_send_header(r); | |
238 | |
239 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
|
240 if (ngx_close_dir(&dir) == NGX_ERROR) { |
090e391f53db
fix file leak for HEAD requests
Igor Sysoev <igor@sysoev.ru>
parents:
842
diff
changeset
|
241 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
|
242 ngx_close_dir_n " \"%V\" failed", &path); |
090e391f53db
fix file leak for HEAD requests
Igor Sysoev <igor@sysoev.ru>
parents:
842
diff
changeset
|
243 } |
090e391f53db
fix file leak for HEAD requests
Igor Sysoev <igor@sysoev.ru>
parents:
842
diff
changeset
|
244 |
523 | 245 return rc; |
246 } | |
247 | |
557 | 248 filename = path.data; |
249 filename[path.len] = '/'; | |
457 | 250 |
2889
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
251 if (r->headers_out.charset.len == 5 |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
252 && 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
|
253 == 0) |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
254 { |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
255 utf8 = 1; |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
256 |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
257 } else { |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
258 utf8 = 0; |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
259 } |
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
260 |
457 | 261 for ( ;; ) { |
262 ngx_set_errno(0); | |
263 | |
264 if (ngx_read_dir(&dir) == NGX_ERROR) { | |
265 err = ngx_errno; | |
266 | |
501 | 267 if (err != NGX_ENOMOREFILES) { |
457 | 268 ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, |
557 | 269 ngx_read_dir_n " \"%V\" failed", &path); |
270 return ngx_http_autoindex_error(r, &dir, &path); | |
457 | 271 } |
272 | |
577 | 273 break; |
457 | 274 } |
275 | |
276 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
277 "http autoindex file: \"%s\"", ngx_de_name(&dir)); | |
278 | |
279 len = ngx_de_namelen(&dir); | |
280 | |
547 | 281 if (ngx_de_name(&dir)[0] == '.') { |
459 | 282 continue; |
283 } | |
284 | |
457 | 285 if (!dir.valid_info) { |
286 | |
557 | 287 /* 1 byte for '/' and 1 byte for terminating '\0' */ |
457 | 288 |
557 | 289 if (path.len + 1 + len + 1 > allocated) { |
290 allocated = path.len + 1 + len + 1 | |
291 + NGX_HTTP_AUTOINDEX_PREALLOCATE; | |
292 | |
2049 | 293 filename = ngx_pnalloc(pool, allocated); |
557 | 294 if (filename == NULL) { |
295 return ngx_http_autoindex_error(r, &dir, &path); | |
457 | 296 } |
297 | |
557 | 298 last = ngx_cpystrn(filename, path.data, path.len + 1); |
457 | 299 *last++ = '/'; |
300 } | |
301 | |
302 ngx_cpystrn(last, ngx_de_name(&dir), len + 1); | |
303 | |
557 | 304 if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { |
497 | 305 err = ngx_errno; |
306 | |
307 if (err != NGX_ENOENT) { | |
308 ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, | |
557 | 309 ngx_de_info_n " \"%s\" failed", filename); |
2371
b438ffe54e34
skip protected symlinks in autoindex
Igor Sysoev <igor@sysoev.ru>
parents:
2125
diff
changeset
|
310 |
b438ffe54e34
skip protected symlinks in autoindex
Igor Sysoev <igor@sysoev.ru>
parents:
2125
diff
changeset
|
311 if (err == NGX_EACCES) { |
b438ffe54e34
skip protected symlinks in autoindex
Igor Sysoev <igor@sysoev.ru>
parents:
2125
diff
changeset
|
312 continue; |
b438ffe54e34
skip protected symlinks in autoindex
Igor Sysoev <igor@sysoev.ru>
parents:
2125
diff
changeset
|
313 } |
b438ffe54e34
skip protected symlinks in autoindex
Igor Sysoev <igor@sysoev.ru>
parents:
2125
diff
changeset
|
314 |
557 | 315 return ngx_http_autoindex_error(r, &dir, &path); |
497 | 316 } |
317 | |
557 | 318 if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { |
497 | 319 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, |
320 ngx_de_link_info_n " \"%s\" failed", | |
557 | 321 filename); |
322 return ngx_http_autoindex_error(r, &dir, &path); | |
497 | 323 } |
457 | 324 } |
325 } | |
326 | |
501 | 327 entry = ngx_array_push(&entries); |
328 if (entry == NULL) { | |
557 | 329 return ngx_http_autoindex_error(r, &dir, &path); |
457 | 330 } |
331 | |
577 | 332 entry->name.len = len; |
525 | 333 |
2049 | 334 entry->name.data = ngx_pnalloc(pool, len + 1); |
501 | 335 if (entry->name.data == NULL) { |
557 | 336 return ngx_http_autoindex_error(r, &dir, &path); |
457 | 337 } |
461 | 338 |
457 | 339 ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); |
340 | |
529 | 341 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
|
342 NGX_ESCAPE_URI_COMPONENT); |
529 | 343 |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
344 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
|
345 entry->name.len); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
346 |
2889
0bb8c54f4c45
refactor ngx_http_charset_header_filter()
Igor Sysoev <igor@sysoev.ru>
parents:
2849
diff
changeset
|
347 if (utf8) { |
2125
8e4b9d2acde8
rename ngx_utf_...() to ngx_utf8_...()
Igor Sysoev <igor@sysoev.ru>
parents:
2120
diff
changeset
|
348 entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len); |
525 | 349 } else { |
350 entry->utf_len = len; | |
351 } | |
352 | |
457 | 353 entry->dir = ngx_de_is_dir(&dir); |
354 entry->mtime = ngx_de_mtime(&dir); | |
355 entry->size = ngx_de_size(&dir); | |
356 } | |
357 | |
358 if (ngx_close_dir(&dir) == NGX_ERROR) { | |
359 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, | |
557 | 360 ngx_close_dir_n " \"%s\" failed", &path); |
457 | 361 } |
362 | |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
363 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
|
364 |
457 | 365 len = sizeof(title) - 1 |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
366 + r->uri.len + escape_html |
457 | 367 + sizeof(header) - 1 |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
368 + r->uri.len + escape_html |
457 | 369 + sizeof("</h1>") - 1 |
370 + sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1 | |
371 + sizeof("</pre><hr>") - 1 | |
372 + sizeof(tail) - 1; | |
373 | |
374 entry = entries.elts; | |
375 for (i = 0; i < entries.nelts; i++) { | |
376 len += sizeof("<a href=\"") - 1 | |
529 | 377 + entry[i].name.len + entry[i].escape |
525 | 378 + 1 /* 1 is for "/" */ |
379 + sizeof("\">") - 1 | |
4192
61e4af19df9f
Autoindex: escape '?' in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
3527
diff
changeset
|
380 + 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
|
381 + entry[i].escape_html |
525 | 382 + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof(">") - 2 |
383 + sizeof("</a>") - 1 | |
384 + sizeof(" 28-Sep-1970 12:00 ") - 1 | |
529 | 385 + 20 /* the file size */ |
525 | 386 + 2; |
457 | 387 } |
388 | |
501 | 389 b = ngx_create_temp_buf(r->pool, len); |
390 if (b == NULL) { | |
457 | 391 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
392 } | |
393 | |
394 if (entries.nelts > 1) { | |
395 ngx_qsort(entry, (size_t) entries.nelts, | |
396 sizeof(ngx_http_autoindex_entry_t), | |
397 ngx_http_autoindex_cmp_entries); | |
398 } | |
399 | |
400 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
|
401 |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
402 if (escape_html) { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
403 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
|
404 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
|
405 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
|
406 |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
407 } else { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
408 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
|
409 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
|
410 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
|
411 } |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
412 |
457 | 413 b->last = ngx_cpymem(b->last, "</h1>", sizeof("</h1>") - 1); |
414 | |
415 b->last = ngx_cpymem(b->last, "<hr><pre><a href=\"../\">../</a>" CRLF, | |
416 sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1); | |
417 | |
563 | 418 tp = ngx_timeofday(); |
419 | |
457 | 420 for (i = 0; i < entries.nelts; i++) { |
421 b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1); | |
461 | 422 |
423 if (entry[i].escape) { | |
424 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
|
425 NGX_ESCAPE_URI_COMPONENT); |
461 | 426 |
427 b->last += entry[i].name.len + entry[i].escape; | |
428 | |
429 } else { | |
430 b->last = ngx_cpymem(b->last, entry[i].name.data, | |
431 entry[i].name.len); | |
432 } | |
457 | 433 |
434 if (entry[i].dir) { | |
435 *b->last++ = '/'; | |
436 } | |
437 | |
438 *b->last++ = '"'; | |
439 *b->last++ = '>'; | |
440 | |
525 | 441 len = entry[i].utf_len; |
457 | 442 |
2120 | 443 if (entry[i].name.len != len) { |
527 | 444 if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
445 char_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3 + 1; |
527 | 446 |
447 } else { | |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
448 char_len = NGX_HTTP_AUTOINDEX_NAME_LEN + 1; |
527 | 449 } |
450 | |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
451 last = b->last; |
2125
8e4b9d2acde8
rename ngx_utf_...() to ngx_utf8_...()
Igor Sysoev <igor@sysoev.ru>
parents:
2120
diff
changeset
|
452 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
|
453 char_len, entry[i].name.len + 1); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
454 |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
455 if (entry[i].escape_html) { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
456 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
|
457 b->last - last); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
458 } |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
459 |
527 | 460 last = b->last; |
461 | |
462 } else { | |
4193
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
463 if (entry[i].escape_html) { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
464 if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
465 char_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3; |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
466 |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
467 } else { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
468 char_len = len; |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
469 } |
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 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
|
472 entry[i].name.data, char_len); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
473 last = b->last; |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
474 |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
475 } else { |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
476 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
|
477 NGX_HTTP_AUTOINDEX_NAME_LEN + 1); |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
478 last = b->last - 3; |
63aa6ab94630
Autoindex: escape html in file names.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4192
diff
changeset
|
479 } |
527 | 480 } |
481 | |
457 | 482 if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { |
527 | 483 b->last = ngx_cpymem(last, "..></a>", sizeof("..></a>") - 1); |
457 | 484 |
485 } else { | |
486 if (entry[i].dir && NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) { | |
487 *b->last++ = '/'; | |
488 len++; | |
489 } | |
490 | |
491 b->last = ngx_cpymem(b->last, "</a>", sizeof("</a>") - 1); | |
492 ngx_memset(b->last, ' ', NGX_HTTP_AUTOINDEX_NAME_LEN - len); | |
493 b->last += NGX_HTTP_AUTOINDEX_NAME_LEN - len; | |
494 } | |
495 | |
496 *b->last++ = ' '; | |
497 | |
563 | 498 ngx_gmtime(entry[i].mtime + tp->gmtoff * 60 * alcf->localtime, &tm); |
457 | 499 |
500 b->last = ngx_sprintf(b->last, "%02d-%s-%d %02d:%02d ", | |
501 tm.ngx_tm_mday, | |
502 months[tm.ngx_tm_mon - 1], | |
503 tm.ngx_tm_year, | |
504 tm.ngx_tm_hour, | |
505 tm.ngx_tm_min); | |
506 | |
527 | 507 if (alcf->exact_size) { |
508 if (entry[i].dir) { | |
509 b->last = ngx_cpymem(b->last, " -", | |
510 sizeof(" -") - 1); | |
511 } else { | |
512 b->last = ngx_sprintf(b->last, "%19O", entry[i].size); | |
577 | 513 } |
457 | 514 |
515 } else { | |
527 | 516 if (entry[i].dir) { |
547 | 517 b->last = ngx_cpymem(b->last, " -", |
518 sizeof(" -") - 1); | |
527 | 519 |
520 } else { | |
521 length = entry[i].size; | |
522 | |
523 if (length > 1024 * 1024 * 1024 - 1) { | |
524 size = (ngx_int_t) (length / (1024 * 1024 * 1024)); | |
525 if ((length % (1024 * 1024 * 1024)) | |
526 > (1024 * 1024 * 1024 / 2 - 1)) | |
577 | 527 { |
527 | 528 size++; |
529 } | |
530 scale = 'G'; | |
531 | |
532 } else if (length > 1024 * 1024 - 1) { | |
533 size = (ngx_int_t) (length / (1024 * 1024)); | |
534 if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) { | |
535 size++; | |
536 } | |
537 scale = 'M'; | |
538 | |
539 } else if (length > 9999) { | |
540 size = (ngx_int_t) (length / 1024); | |
541 if (length % 1024 > 511) { | |
542 size++; | |
543 } | |
544 scale = 'K'; | |
545 | |
546 } else { | |
547 size = (ngx_int_t) length; | |
547 | 548 scale = '\0'; |
527 | 549 } |
550 | |
547 | 551 if (scale) { |
552 b->last = ngx_sprintf(b->last, "%6i%c", size, scale); | |
527 | 553 |
547 | 554 } else { |
555 b->last = ngx_sprintf(b->last, " %6i", size); | |
527 | 556 } |
557 } | |
457 | 558 } |
559 | |
560 *b->last++ = CR; | |
561 *b->last++ = LF; | |
562 } | |
563 | |
459 | 564 /* TODO: free temporary pool */ |
565 | |
457 | 566 b->last = ngx_cpymem(b->last, "</pre><hr>", sizeof("</pre><hr>") - 1); |
567 | |
568 b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1); | |
569 | |
597 | 570 if (r == r->main) { |
457 | 571 b->last_buf = 1; |
572 } | |
573 | |
509 | 574 b->last_in_chain = 1; |
575 | |
457 | 576 out.buf = b; |
577 out.next = NULL; | |
578 | |
579 return ngx_http_output_filter(r, &out); | |
580 } | |
581 | |
582 | |
503 | 583 static int ngx_libc_cdecl |
499 | 584 ngx_http_autoindex_cmp_entries(const void *one, const void *two) |
457 | 585 { |
586 ngx_http_autoindex_entry_t *first = (ngx_http_autoindex_entry_t *) one; | |
587 ngx_http_autoindex_entry_t *second = (ngx_http_autoindex_entry_t *) two; | |
588 | |
589 if (first->dir && !second->dir) { | |
590 /* move the directories to the start */ | |
591 return -1; | |
592 } | |
593 | |
594 if (!first->dir && second->dir) { | |
595 /* move the directories to the start */ | |
596 return 1; | |
597 } | |
598 | |
599 return (int) ngx_strcmp(first->name.data, second->name.data); | |
600 } | |
601 | |
602 | |
603 #if 0 | |
604 | |
499 | 605 static ngx_buf_t * |
606 ngx_http_autoindex_alloc(ngx_http_autoindex_ctx_t *ctx, size_t size) | |
457 | 607 { |
608 ngx_chain_t *cl; | |
609 | |
610 if (ctx->buf) { | |
611 | |
612 if ((size_t) (ctx->buf->end - ctx->buf->last) >= size) { | |
613 return ctx->buf; | |
614 } | |
615 | |
616 ctx->size += ctx->buf->last - ctx->buf->pos; | |
617 } | |
618 | |
501 | 619 ctx->buf = ngx_create_temp_buf(ctx->pool, ctx->alloc_size); |
620 if (ctx->buf == NULL) { | |
457 | 621 return NULL; |
622 } | |
623 | |
501 | 624 cl = ngx_alloc_chain_link(ctx->pool); |
625 if (cl == NULL) { | |
457 | 626 return NULL; |
627 } | |
628 | |
629 cl->buf = ctx->buf; | |
630 cl->next = NULL; | |
631 | |
632 *ctx->last_out = cl; | |
633 ctx->last_out = &cl->next; | |
634 | |
635 return ctx->buf; | |
636 } | |
637 | |
638 #endif | |
639 | |
640 | |
499 | 641 static ngx_int_t |
557 | 642 ngx_http_autoindex_error(ngx_http_request_t *r, ngx_dir_t *dir, ngx_str_t *name) |
457 | 643 { |
644 if (ngx_close_dir(dir) == NGX_ERROR) { | |
645 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, | |
557 | 646 ngx_close_dir_n " \"%V\" failed", name); |
457 | 647 } |
648 | |
649 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
650 } | |
651 | |
652 | |
499 | 653 static void * |
654 ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf) | |
457 | 655 { |
656 ngx_http_autoindex_loc_conf_t *conf; | |
657 | |
658 conf = ngx_palloc(cf->pool, sizeof(ngx_http_autoindex_loc_conf_t)); | |
659 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
|
660 return NULL; |
457 | 661 } |
662 | |
663 conf->enable = NGX_CONF_UNSET; | |
519 | 664 conf->localtime = NGX_CONF_UNSET; |
527 | 665 conf->exact_size = NGX_CONF_UNSET; |
457 | 666 |
667 return conf; | |
668 } | |
669 | |
670 | |
499 | 671 static char * |
672 ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) | |
457 | 673 { |
674 ngx_http_autoindex_loc_conf_t *prev = parent; | |
675 ngx_http_autoindex_loc_conf_t *conf = child; | |
676 | |
677 ngx_conf_merge_value(conf->enable, prev->enable, 0); | |
519 | 678 ngx_conf_merge_value(conf->localtime, prev->localtime, 0); |
527 | 679 ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1); |
457 | 680 |
681 return NGX_CONF_OK; | |
682 } | |
681 | 683 |
684 | |
685 static ngx_int_t | |
686 ngx_http_autoindex_init(ngx_conf_t *cf) | |
687 { | |
688 ngx_http_handler_pt *h; | |
689 ngx_http_core_main_conf_t *cmcf; | |
690 | |
691 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); | |
692 | |
693 h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); | |
694 if (h == NULL) { | |
695 return NGX_ERROR; | |
696 } | |
697 | |
698 *h = ngx_http_autoindex_handler; | |
699 | |
700 return NGX_OK; | |
701 } |