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