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("&gt;") - 2 381 + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof("&gt;") - 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, "..&gt;</a>", sizeof("..&gt;</a>") - 1); 482 b->last = ngx_cpymem(last, "..&gt;</a>", sizeof("..&gt;</a>") - 1);
454 483