Mercurial > hg > nginx
comparison src/http/modules/ngx_http_autoindex_module.c @ 4253:6efec8b1ff52 stable-1.0
Merging r4193, r4194:
Autoindex fixes:
*) Autoindex: escape '?' in file names.
For files with '?' in their names autoindex generated links with '?' not
escaped. This resulted in effectively truncated links as '?' indicates
query string start.
This is an updated version of the patch originally posted at [1]. It
introduces generic NGX_ESCAPE_URI_COMPONENT which escapes everything but
unreserved characters as per RFC 3986. This approach also renders unneeded
special colon processing (as colon is percent-encoded now), it's dropped
accordingly.
[1] http://nginx.org/pipermail/nginx-devel/2010-February/000112.html
*) Autoindex: escape html in file names.
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Tue, 01 Nov 2011 14:09:15 +0000 |
parents | 84905c7b2aa7 |
children | 4919fb357a5d |
comparison
equal
deleted
inserted
replaced
4252:94049ec3eeda | 4253:6efec8b1ff52 |
---|---|
24 | 24 |
25 typedef struct { | 25 typedef struct { |
26 ngx_str_t name; | 26 ngx_str_t name; |
27 size_t utf_len; | 27 size_t utf_len; |
28 size_t escape; | 28 size_t escape; |
29 size_t escape_html; | |
29 | 30 |
30 unsigned dir:1; | 31 unsigned dir:1; |
31 unsigned colon:1; | |
32 | 32 |
33 time_t mtime; | 33 time_t mtime; |
34 off_t size; | 34 off_t size; |
35 } ngx_http_autoindex_entry_t; | 35 } ngx_http_autoindex_entry_t; |
36 | 36 |
136 static ngx_int_t | 136 static ngx_int_t |
137 ngx_http_autoindex_handler(ngx_http_request_t *r) | 137 ngx_http_autoindex_handler(ngx_http_request_t *r) |
138 { | 138 { |
139 u_char *last, *filename, scale; | 139 u_char *last, *filename, scale; |
140 off_t length; | 140 off_t length; |
141 size_t len, utf_len, allocated, root; | 141 size_t len, char_len, escape_html, allocated, root; |
142 ngx_tm_t tm; | 142 ngx_tm_t tm; |
143 ngx_err_t err; | 143 ngx_err_t err; |
144 ngx_buf_t *b; | 144 ngx_buf_t *b; |
145 ngx_int_t rc, size; | 145 ngx_int_t rc, size; |
146 ngx_str_t path; | 146 ngx_str_t path; |
336 } | 336 } |
337 | 337 |
338 ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); | 338 ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); |
339 | 339 |
340 entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len, | 340 entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len, |
341 NGX_ESCAPE_HTML); | 341 NGX_ESCAPE_URI_COMPONENT); |
342 | |
343 entry->escape_html = ngx_escape_html(NULL, entry->name.data, | |
344 entry->name.len); | |
342 | 345 |
343 if (utf8) { | 346 if (utf8) { |
344 entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len); | 347 entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len); |
345 } else { | 348 } else { |
346 entry->utf_len = len; | 349 entry->utf_len = len; |
347 } | 350 } |
348 | 351 |
349 entry->colon = (ngx_strchr(entry->name.data, ':') != NULL); | |
350 | |
351 entry->dir = ngx_de_is_dir(&dir); | 352 entry->dir = ngx_de_is_dir(&dir); |
352 entry->mtime = ngx_de_mtime(&dir); | 353 entry->mtime = ngx_de_mtime(&dir); |
353 entry->size = ngx_de_size(&dir); | 354 entry->size = ngx_de_size(&dir); |
354 } | 355 } |
355 | 356 |
356 if (ngx_close_dir(&dir) == NGX_ERROR) { | 357 if (ngx_close_dir(&dir) == NGX_ERROR) { |
357 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, | 358 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, |
358 ngx_close_dir_n " \"%s\" failed", &path); | 359 ngx_close_dir_n " \"%s\" failed", &path); |
359 } | 360 } |
360 | 361 |
362 escape_html = ngx_escape_html(NULL, r->uri.data, r->uri.len); | |
363 | |
361 len = sizeof(title) - 1 | 364 len = sizeof(title) - 1 |
362 + r->uri.len | 365 + r->uri.len + escape_html |
363 + sizeof(header) - 1 | 366 + sizeof(header) - 1 |
364 + r->uri.len | 367 + r->uri.len + escape_html |
365 + sizeof("</h1>") - 1 | 368 + sizeof("</h1>") - 1 |
366 + sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1 | 369 + sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1 |
367 + sizeof("</pre><hr>") - 1 | 370 + sizeof("</pre><hr>") - 1 |
368 + sizeof(tail) - 1; | 371 + sizeof(tail) - 1; |
369 | 372 |
371 for (i = 0; i < entries.nelts; i++) { | 374 for (i = 0; i < entries.nelts; i++) { |
372 len += sizeof("<a href=\"") - 1 | 375 len += sizeof("<a href=\"") - 1 |
373 + entry[i].name.len + entry[i].escape | 376 + entry[i].name.len + entry[i].escape |
374 + 1 /* 1 is for "/" */ | 377 + 1 /* 1 is for "/" */ |
375 + sizeof("\">") - 1 | 378 + sizeof("\">") - 1 |
376 + entry[i].name.len - entry[i].utf_len + entry[i].colon * 2 | 379 + entry[i].name.len - entry[i].utf_len |
380 + entry[i].escape_html | |
377 + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof(">") - 2 | 381 + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof(">") - 2 |
378 + sizeof("</a>") - 1 | 382 + sizeof("</a>") - 1 |
379 + sizeof(" 28-Sep-1970 12:00 ") - 1 | 383 + sizeof(" 28-Sep-1970 12:00 ") - 1 |
380 + 20 /* the file size */ | 384 + 20 /* the file size */ |
381 + 2; | 385 + 2; |
391 sizeof(ngx_http_autoindex_entry_t), | 395 sizeof(ngx_http_autoindex_entry_t), |
392 ngx_http_autoindex_cmp_entries); | 396 ngx_http_autoindex_cmp_entries); |
393 } | 397 } |
394 | 398 |
395 b->last = ngx_cpymem(b->last, title, sizeof(title) - 1); | 399 b->last = ngx_cpymem(b->last, title, sizeof(title) - 1); |
396 b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); | 400 |
397 b->last = ngx_cpymem(b->last, header, sizeof(header) - 1); | 401 if (escape_html) { |
398 b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); | 402 b->last = (u_char *) ngx_escape_html(b->last, r->uri.data, r->uri.len); |
403 b->last = ngx_cpymem(b->last, header, sizeof(header) - 1); | |
404 b->last = (u_char *) ngx_escape_html(b->last, r->uri.data, r->uri.len); | |
405 | |
406 } else { | |
407 b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); | |
408 b->last = ngx_cpymem(b->last, header, sizeof(header) - 1); | |
409 b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); | |
410 } | |
411 | |
399 b->last = ngx_cpymem(b->last, "</h1>", sizeof("</h1>") - 1); | 412 b->last = ngx_cpymem(b->last, "</h1>", sizeof("</h1>") - 1); |
400 | 413 |
401 b->last = ngx_cpymem(b->last, "<hr><pre><a href=\"../\">../</a>" CRLF, | 414 b->last = ngx_cpymem(b->last, "<hr><pre><a href=\"../\">../</a>" CRLF, |
402 sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1); | 415 sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1); |
403 | 416 |
404 tp = ngx_timeofday(); | 417 tp = ngx_timeofday(); |
405 | 418 |
406 for (i = 0; i < entries.nelts; i++) { | 419 for (i = 0; i < entries.nelts; i++) { |
407 b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1); | 420 b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1); |
408 | 421 |
409 if (entry[i].colon) { | |
410 *b->last++ = '.'; | |
411 *b->last++ = '/'; | |
412 } | |
413 | |
414 if (entry[i].escape) { | 422 if (entry[i].escape) { |
415 ngx_escape_uri(b->last, entry[i].name.data, entry[i].name.len, | 423 ngx_escape_uri(b->last, entry[i].name.data, entry[i].name.len, |
416 NGX_ESCAPE_HTML); | 424 NGX_ESCAPE_URI_COMPONENT); |
417 | 425 |
418 b->last += entry[i].name.len + entry[i].escape; | 426 b->last += entry[i].name.len + entry[i].escape; |
419 | 427 |
420 } else { | 428 } else { |
421 b->last = ngx_cpymem(b->last, entry[i].name.data, | 429 b->last = ngx_cpymem(b->last, entry[i].name.data, |
431 | 439 |
432 len = entry[i].utf_len; | 440 len = entry[i].utf_len; |
433 | 441 |
434 if (entry[i].name.len != len) { | 442 if (entry[i].name.len != len) { |
435 if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { | 443 if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { |
436 utf_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3 + 1; | 444 char_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3 + 1; |
437 | 445 |
438 } else { | 446 } else { |
439 utf_len = NGX_HTTP_AUTOINDEX_NAME_LEN + 1; | 447 char_len = NGX_HTTP_AUTOINDEX_NAME_LEN + 1; |
440 } | 448 } |
441 | 449 |
450 last = b->last; | |
442 b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data, | 451 b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data, |
443 utf_len, entry[i].name.len + 1); | 452 char_len, entry[i].name.len + 1); |
453 | |
454 if (entry[i].escape_html) { | |
455 b->last = (u_char *) ngx_escape_html(last, entry[i].name.data, | |
456 b->last - last); | |
457 } | |
458 | |
444 last = b->last; | 459 last = b->last; |
445 | 460 |
446 } else { | 461 } else { |
447 b->last = ngx_cpystrn(b->last, entry[i].name.data, | 462 if (entry[i].escape_html) { |
448 NGX_HTTP_AUTOINDEX_NAME_LEN + 1); | 463 if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { |
449 last = b->last - 3; | 464 char_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3; |
465 | |
466 } else { | |
467 char_len = len; | |
468 } | |
469 | |
470 b->last = (u_char *) ngx_escape_html(b->last, | |
471 entry[i].name.data, char_len); | |
472 last = b->last; | |
473 | |
474 } else { | |
475 b->last = ngx_cpystrn(b->last, entry[i].name.data, | |
476 NGX_HTTP_AUTOINDEX_NAME_LEN + 1); | |
477 last = b->last - 3; | |
478 } | |
450 } | 479 } |
451 | 480 |
452 if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { | 481 if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { |
453 b->last = ngx_cpymem(last, "..></a>", sizeof("..></a>") - 1); | 482 b->last = ngx_cpymem(last, "..></a>", sizeof("..></a>") - 1); |
454 | 483 |