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

Reported by Konstantin Leonov.
This commit is contained in:
Maxim Dounin 2011-10-11 17:56:51 +00:00
parent 3a547a0e7e
commit 103eeafae7
3 changed files with 31 additions and 18 deletions

View file

@ -1374,6 +1374,26 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
/* ~}| {zyx wvut srqp onml kjih gfed cba` */
0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
};
/* not ALPHA, DIGIT, "-", ".", "_", "~" */
static uint32_t uri_component[] = {
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
/* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
0xfc009fff, /* 1111 1100 0000 0000 1001 1111 1111 1111 */
/* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
0x78000001, /* 0111 1000 0000 0000 0000 0000 0000 0001 */
/* ~}| {zyx wvut srqp onml kjih gfed cba` */
0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
@ -1443,7 +1463,7 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
/* mail_auth is the same as memcached */
static uint32_t *map[] =
{ uri, args, html, refresh, memcached, memcached };
{ uri, args, uri_component, html, refresh, memcached, memcached };
escape = map[type];

View file

@ -191,10 +191,11 @@ u_char *ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len);
#define NGX_ESCAPE_URI 0
#define NGX_ESCAPE_ARGS 1
#define NGX_ESCAPE_HTML 2
#define NGX_ESCAPE_REFRESH 3
#define NGX_ESCAPE_MEMCACHED 4
#define NGX_ESCAPE_MAIL_AUTH 5
#define NGX_ESCAPE_URI_COMPONENT 2
#define NGX_ESCAPE_HTML 3
#define NGX_ESCAPE_REFRESH 4
#define NGX_ESCAPE_MEMCACHED 5
#define NGX_ESCAPE_MAIL_AUTH 6
#define NGX_UNESCAPE_URI 1
#define NGX_UNESCAPE_REDIRECT 2

View file

@ -28,7 +28,6 @@ typedef struct {
size_t escape;
unsigned dir:1;
unsigned colon:1;
time_t mtime;
off_t size;
@ -338,7 +337,7 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1);
entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len,
NGX_ESCAPE_HTML);
NGX_ESCAPE_URI_COMPONENT);
if (utf8) {
entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len);
@ -346,8 +345,6 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
entry->utf_len = len;
}
entry->colon = (ngx_strchr(entry->name.data, ':') != NULL);
entry->dir = ngx_de_is_dir(&dir);
entry->mtime = ngx_de_mtime(&dir);
entry->size = ngx_de_size(&dir);
@ -373,7 +370,7 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
+ entry[i].name.len + entry[i].escape
+ 1 /* 1 is for "/" */
+ sizeof("\">") - 1
+ entry[i].name.len - entry[i].utf_len + entry[i].colon * 2
+ entry[i].name.len - entry[i].utf_len
+ NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof("&gt;") - 2
+ sizeof("</a>") - 1
+ sizeof(" 28-Sep-1970 12:00 ") - 1
@ -406,14 +403,9 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
for (i = 0; i < entries.nelts; i++) {
b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1);
if (entry[i].colon) {
*b->last++ = '.';
*b->last++ = '/';
}
if (entry[i].escape) {
ngx_escape_uri(b->last, entry[i].name.data, entry[i].name.len,
NGX_ESCAPE_HTML);
NGX_ESCAPE_URI_COMPONENT);
b->last += entry[i].name.len + entry[i].escape;