changeset 6:80ba094c6b3e NGINX_0_1_3

nginx 0.1.3 *) Feature: the ngx_http_autoindex_module and the autoindex directive. *) Feature: the proxy_set_x_url directive. *) Bugfix: proxy module may get caught in an endless loop when sendfile is not used.
author Igor Sysoev <http://sysoev.ru>
date Mon, 25 Oct 2004 00:00:00 +0400
parents 985c56ebe724
children 2cb393a33bee
files CHANGES CHANGES.ru auto/modules auto/options auto/sources auto/summary auto/threads configure src/core/nginx.h src/core/ngx_file.h src/core/ngx_garbage_collector.c src/core/ngx_string.c src/event/ngx_event_connect.h src/event/ngx_event_pipe.c src/http/modules/ngx_http_autoindex_handler.c src/http/modules/ngx_http_index_handler.c src/http/modules/proxy/ngx_http_proxy_handler.c src/http/modules/proxy/ngx_http_proxy_handler.h src/http/modules/proxy/ngx_http_proxy_upstream.c src/http/ngx_http_core_module.c src/http/ngx_http_header_filter.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/os/unix/ngx_errno.c src/os/unix/ngx_errno.h src/os/unix/ngx_files.c src/os/unix/ngx_files.h src/os/unix/ngx_types.h
diffstat 28 files changed, 765 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,13 @@
+
+Changes with nginx 0.1.3                                         25 Oct 2004
+
+    *) Feature: the ngx_http_autoindex_module and the autoindex directive.
+
+    *) Feature: the proxy_set_x_url directive.
+
+    *) Bugfix: proxy module may get caught in an endless loop when sendfile 
+       is not used.
+
 
 Changes with nginx 0.1.2                                         21 Oct 2004
 
@@ -9,13 +19,13 @@ Changes with nginx 0.1.2                
     *) Bugfix: the portability improvements.
 
     *) Bugfix: if configuration file was set in command line, the 
-       reconfiguration was impossible, bug appeared in 0.1.1.
+       reconfiguration was impossible; bug appeared in 0.1.1.
 
     *) Bugfix: proxy module may get caught in an endless loop when sendfile 
        is not used.
 
     *) Bugfix: with sendfile the response was not recoded according to the 
-       charset module directives, bug appeared in 0.1.1.
+       charset module directives; bug appeared in 0.1.1.
 
     *) Bugfix: very seldom bug in the kqueue processing.
 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,3 +1,13 @@
+
+Изменения в nginx 0.1.3                                           25.10.2004
+
+    *) Добавление: модуль ngx_http_autoindex_module и директива autoindex.
+
+    *) Добавление: директива proxy_set_x_url.
+
+    *) Исправление: модуль проксировании мог привести к зацикливанию, если не 
+       использовался sendfile.
+
 
 Изменения в nginx 0.1.2                                           21.10.2004
 
@@ -9,13 +19,13 @@
     *) Исправление: улучшена переносимость на неизвестные платформы.
 
     *) Исправление: нельзя переконфигурировать nginx, если конфигурационный 
-       файл указан в командной строке, ошибка появилась в 0.1.1.
+       файл указан в командной строке; ошибка появилась в 0.1.1.
 
     *) Исправление: модуль проксировании мог привести к зацикливанию, если не 
        использовался sendfile.
 
     *) Исправление: при использовании sendfile текст ответа не 
-       перекодировался согласно директивам модуля charset, ошибка появилась в 
+       перекодировался согласно директивам модуля charset; ошибка появилась в 
        0.1.1.
 
     *) Исправление: очень редкая ошибка при обработке kqueue.
--- a/auto/modules
+++ b/auto/modules
@@ -87,7 +87,15 @@ if [ $HTTP_USERID = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_USERID_SRCS"
 fi
 
-HTTP_MODULES="$HTTP_MODULES $HTTP_STATIC_MODULE $HTTP_INDEX_MODULE"
+HTTP_MODULES="$HTTP_MODULES $HTTP_STATIC_MODULE"
+
+if [ $HTTP_AUTOINDEX = YES ]; then
+    have=NGX_HTTP_AUTOINDEX . auto/have
+    HTTP_MODULES="$HTTP_MODULES $HTTP_AUTOINDEX_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_AUTOINDEX_SRCS"
+fi
+
+HTTP_MODULES="$HTTP_MODULES $HTTP_INDEX_MODULE"
 
 if [ $HTTP_ACCESS = YES ]; then
     have=NGX_HTTP_ACCESS . auto/have
--- a/auto/options
+++ b/auto/options
@@ -42,6 +42,7 @@ HTTP_SSL=NO
 HTTP_SSI=NO
 HTTP_ACCESS=YES
 HTTP_USERID=YES
+HTTP_AUTOINDEX=YES
 HTTP_STATUS=NO
 HTTP_REWRITE=YES
 HTTP_PROXY=YES
@@ -107,6 +108,7 @@ do
         --without-http_ssi_module)       HTTP_SSI=NO                ;;
         --without-http_userid_module)    HTTP_USERID=NO             ;;
         --without-http_access_module)    HTTP_ACCESS=NO             ;;
+        --without-http_autoindex_module) HTTP_AUTOINDEX=NO          ;;
         --without-http_status_module)    HTTP_STATUS=NO             ;;
         --without-http_rewrite_module)   HTTP_REWRITE=NO            ;;
         --without-http_proxy_module)     HTTP_PROXY=NO              ;;
--- a/auto/sources
+++ b/auto/sources
@@ -272,6 +272,10 @@ HTTP_ACCESS_MODULE=ngx_http_access_modul
 HTTP_ACCESS_SRCS=src/http/modules/ngx_http_access_handler.c
 
 
+HTTP_AUTOINDEX_MODULE=ngx_http_autoindex_module
+HTTP_AUTOINDEX_SRCS=src/http/modules/ngx_http_autoindex_handler.c
+
+
 HTTP_STATUS_MODULE=ngx_http_status_module
 HTTP_STATUS_SRCS=src/http/modules/ngx_http_status_handler.c
 
--- a/auto/summary
+++ b/auto/summary
@@ -6,6 +6,16 @@ echo
 echo "Configuration summary"
 
 
+case $USE_THREADS in
+    rfork)         echo "  + using rfork()ed threads" ;;
+    pthreads)      echo "  + using libpthread threads library" ;;
+    libthr)        echo "  + using FreeBSD libthr threads library" ;;
+    libc_r)        echo "  + using FreeBSD libc_r threads library" ;;
+    linuxthreads)  echo "  + using FreeBSD LinuxThreads port library" ;;
+    NO)            echo "  + threads are not used" ;;
+    *)             echo "  + using lib$USE_THREADS threads library" ;;
+esac
+
 if [ $USE_PCRE = DISABLED ]; then
     echo " + PCRE library is disabled"
 
--- a/auto/threads
+++ b/auto/threads
@@ -20,17 +20,16 @@ case $USE_THREADS in
         esac
     ;;
 
-    pthread)
+    pthreads)
         have=NGX_THREADS . auto/have
         CORE_SRCS="$CORE_SRCS $PTHREAD_SRCS"
         CORE_LIBS="$CORE_LIBS -lpthread"
     ;;
 
-    freebsd4)
+    libthr)
         have=NGX_THREADS . auto/have
-        CFLAGS="$CFLAGS -pthread"
         CORE_SRCS="$CORE_SRCS $PTHREAD_SRCS"
-        CORE_LIBS="$CORE_LIBS -pthread"
+        CORE_LIBS="$CORE_LIBS -lthr"
     ;;
 
     linuxthreads)
@@ -42,22 +41,30 @@ case $USE_THREADS in
         CORE_LIBS="$CORE_LIBS -L /usr/local/lib -llthread -llgcc_r"
     ;;
 
-    lc_r)
-        have=NGX_THREADS . auto/have
-        CORE_SRCS="$CORE_SRCS $PTHREAD_SRCS"
-        CORE_LIBS="$CORE_LIBS -lc_r"
+    libc_r)
+        case $PLATFORM in
+            FreeBSD:[34]*)
+                have=NGX_THREADS . auto/have
+                CFLAGS="$CFLAGS -pthread"
+                CORE_SRCS="$CORE_SRCS $PTHREAD_SRCS"
+                CORE_LIBS="$CORE_LIBS -pthread"
+            ;;
+
+            FreeBSD:5*)
+                have=NGX_THREADS . auto/have
+                CORE_SRCS="$CORE_SRCS $PTHREAD_SRCS"
+                CORE_LIBS="$CORE_LIBS -lc_r"
+            ;;
+        esac
     ;;
 
-    lthr)
+    NO)
+    ;;
+
+    *)
         have=NGX_THREADS . auto/have
         CORE_SRCS="$CORE_SRCS $PTHREAD_SRCS"
-        CORE_LIBS="$CORE_LIBS -lthr"
-    ;;
-
-    lkse)
-        have=NGX_THREADS . auto/have
-        CORE_SRCS="$CORE_SRCS $PTHREAD_SRCS"
-        CORE_LIBS="$CORE_LIBS -lkse"
+        CORE_LIBS="$CORE_LIBS -l$USE_THREADS"
     ;;
 
 esac
--- a/configure
+++ b/configure
@@ -23,13 +23,14 @@ fi
 
 . auto/cc/conf
 . auto/os/conf
-. auto/modules
-. auto/lib/conf
 
 if [ "$PLATFORM" != win32 ]; then
     . auto/threads
 fi
 
+. auto/modules
+. auto/lib/conf
+
 . auto/make
 . auto/lib/make
 . auto/install
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.1.2"
+#define NGINX_VER          "nginx/0.1.3"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_NEWPID_EXT     ".newbin"
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -26,7 +26,7 @@ struct ngx_file_s {
 
     ngx_log_t       *log;
 
-    unsigned         info_valid:1;
+    ngx_uint_t       valid_info:1;  /* unsigned  valid_info:1; */
 };
 
 #define NGX_MAX_PATH_LEVEL  3
--- a/src/core/ngx_garbage_collector.c
+++ b/src/core/ngx_garbage_collector.c
@@ -153,7 +153,7 @@ static int ngx_collect_garbage(ngx_gc_t 
         ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
                        "gc path: \"%s\"", fname.data);
 
-        if (!dir.info_valid) {
+        if (!dir.valid_info) {
             if (ngx_de_info(fname.data, &dir) == NGX_FILE_ERROR) {
                 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
                               ngx_de_info_n " \"%s\" failed", fname.data);
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -41,6 +41,7 @@ u_char *ngx_cpystrn(u_char *dst, u_char 
  *    %[0][width]ui    ngx_uint_t
  *    %[0][width]uxi   ngx_uint_t in hex
  *    %s               null-terminated string
+ *    %c               char
  *    %%               %
  *
  */
@@ -223,6 +224,13 @@ u_char *ngx_sprintf(u_char *buf, char *f
 
                 continue;
 
+            case 'c':
+                d = va_arg(arg, int);
+                *buf++ = (u_char) (d & 0xff);
+                fmt++;
+
+                continue;
+
             case '%':
                 *buf++ = '%';
                 fmt++;
--- a/src/event/ngx_event_connect.h
+++ b/src/event/ngx_event_connect.h
@@ -31,7 +31,7 @@ typedef struct {
     ngx_int_t           current;
     ngx_int_t           number;
     ngx_int_t           max_fails;
-    ngx_int_t           fail_timeout;
+    time_t              fail_timeout;
     ngx_int_t           last_cached;
 
  /* ngx_mutex_t        *mutex; */
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -619,6 +619,8 @@ static ngx_int_t ngx_event_pipe_write_ch
 
         b->in_file = 1;
         b->temp_file = 1;
+        b->temporary = 0;
+        b->recycled = 0;
 
         ngx_chain_add_link(p->out, p->last_out, cl);
 
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_autoindex_handler.c
@@ -0,0 +1,560 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+#if 0
+
+typedef struct {
+    ngx_buf_t     *buf;
+    size_t         size;
+    ngx_pool_t    *pool;
+    size_t         alloc_size;
+    ngx_chain_t  **last_out;
+} ngx_http_autoindex_ctx_t;
+
+#endif
+
+
+typedef struct {
+    ngx_str_t      name;
+    ngx_uint_t     dir;
+    time_t         mtime;
+    off_t          size;
+} ngx_http_autoindex_entry_t;
+
+
+typedef struct {
+    ngx_flag_t     enable;
+} ngx_http_autoindex_loc_conf_t;
+
+
+#define NGX_HTTP_AUTOINDEX_NAME_LEN  50
+
+
+static int ngx_http_autoindex_cmp_entries(const void *one, const void *two);
+static ngx_int_t ngx_http_autoindex_error(ngx_http_request_t *r, ngx_dir_t *dir,
+                                          u_char *name);
+static ngx_int_t ngx_http_autoindex_init(ngx_cycle_t *cycle);
+static void *ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf,
+                                               void *parent, void *child);
+
+
+static ngx_command_t  ngx_http_autoindex_commands[] = {
+
+    { ngx_string("autoindex"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_autoindex_loc_conf_t, enable),
+      NULL },
+
+      ngx_null_command
+};
+
+
+ngx_http_module_t  ngx_http_autoindex_module_ctx = {
+    NULL,                                  /* pre conf */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    ngx_http_autoindex_create_loc_conf,    /* create location configration */
+    ngx_http_autoindex_merge_loc_conf      /* merge location configration */
+};
+
+
+ngx_module_t  ngx_http_autoindex_module = {
+    NGX_MODULE,
+    &ngx_http_autoindex_module_ctx,        /* module context */ 
+    ngx_http_autoindex_commands,           /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    ngx_http_autoindex_init,               /* init module */
+    NULL                                   /* init child */
+};
+
+
+static u_char title[] =
+"<html>" CRLF
+"<head><title>Index of "
+;
+
+
+static u_char header[] =
+"</title></head>" CRLF
+"<body bgcolor=\"white\">" CRLF
+"<h1>Index of "
+;
+
+static u_char tail[] =
+"</body>" CRLF
+"</html>" CRLF
+;
+
+
+static ngx_int_t ngx_http_autoindex_handler(ngx_http_request_t *r)
+{
+    u_char                         *last, scale;
+    size_t                          len;
+    off_t                           length;
+    ngx_tm_t                        tm;
+    ngx_int_t                       rc, size;
+    ngx_uint_t                      i, level;
+    ngx_err_t                       err;
+    ngx_buf_t                      *b;
+    ngx_chain_t                     out;
+    ngx_str_t                       dname, fname;
+    ngx_dir_t                       dir;
+    ngx_pool_t                     *pool;
+    ngx_array_t                     entries;
+    ngx_http_core_loc_conf_t       *clcf;
+    ngx_http_autoindex_entry_t     *entry;
+    ngx_http_autoindex_loc_conf_t  *alcf;
+
+    static char  *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+                               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+    if (r->uri.data[r->uri.len - 1] != '/') {
+        return NGX_DECLINED;
+    }
+
+    alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module);
+
+    if (!alcf->enable) {
+        return NGX_DECLINED;
+    }
+
+    /* TODO: pool should be temporary pool */
+    pool = r->pool;
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (clcf->alias) {
+        dname.data = ngx_palloc(pool, clcf->root.len + r->uri.len
+                                                     + NGX_DIR_MASK_LEN
+                                                     - clcf->name.len);
+        if (dname.data == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+    
+        last = ngx_cpymem(dname.data, clcf->root.data, clcf->root.len);
+        last = ngx_cpystrn(last, r->uri.data + clcf->name.len,
+                           r->uri.len - clcf->name.len);
+
+    } else {
+        dname.data = ngx_palloc(pool, clcf->root.len + r->uri.len
+                                                     + NGX_DIR_MASK_LEN);
+        if (dname.data == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        last = ngx_cpymem(dname.data, clcf->root.data, clcf->root.len);
+        last = ngx_cpystrn(last, r->uri.data, r->uri.len);
+
+    }
+
+    dname.len = last - dname.data;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http autoindex: \"%s\"", dname.data);
+
+
+    if (ngx_open_dir(&dname, &dir) == NGX_ERROR) {
+        err = ngx_errno;
+
+        if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
+            level = NGX_LOG_ERR;
+            rc = NGX_HTTP_NOT_FOUND;
+
+        } else if (err == NGX_EACCES) {
+            level = NGX_LOG_ERR;
+            rc = NGX_HTTP_FORBIDDEN;
+
+        } else {
+            level = NGX_LOG_CRIT;
+            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        ngx_log_error(level, r->connection->log, err,
+                      ngx_open_dir_n " \"%s\" failed", dname.data);
+
+        return rc;
+    }
+
+#if (NGX_SUPPRESS_WARN)
+    /* MSVC thinks 'entries' may be used without having been initialized */
+    ngx_memzero(&entries, sizeof(ngx_array_t));
+#endif
+
+    if (ngx_array_init(&entries, pool, 50, sizeof(ngx_http_autoindex_entry_t))
+                                                                  == NGX_ERROR)
+    {
+        return ngx_http_autoindex_error(r, &dir, dname.data);
+    }
+
+    fname.len = 0;
+#if (NGX_SUPPRESS_WARN)
+    fname.data = NULL;
+#endif
+
+    for ( ;; ) {
+        ngx_set_errno(0);
+
+        if (ngx_read_dir(&dir) == NGX_ERROR) {
+            err = ngx_errno;
+
+            if (err == NGX_ENOMOREFILES) {
+                rc = NGX_OK;
+
+            } else {
+                ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
+                              ngx_read_dir_n " \"%s\" failed", dname.data);
+                return ngx_http_autoindex_error(r, &dir, dname.data);
+            }
+
+            break; 
+        }
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http autoindex file: \"%s\"", ngx_de_name(&dir));
+
+        len = ngx_de_namelen(&dir);
+
+        if (!dir.valid_info) {
+
+            if (dname.len + 1 + len > fname.len) {
+                fname.len = dname.len + 1 + len + 32;
+
+                if (!(fname.data = ngx_palloc(pool, fname.len))) {
+                    return ngx_http_autoindex_error(r, &dir, dname.data);
+                }
+
+                last = ngx_cpystrn(fname.data, dname.data,
+                                   dname.len + 1);
+                *last++ = '/';
+            }
+
+            ngx_cpystrn(last, ngx_de_name(&dir), len + 1);
+
+            if (ngx_de_info(fname.data, &dir) == NGX_FILE_ERROR) {
+                ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+                              ngx_de_info_n " \"%s\" failed", fname.data);
+                return ngx_http_autoindex_error(r, &dir, dname.data);
+            }
+        }
+
+        if (len == 1 && ngx_de_name(&dir)[0] == '.') {
+            continue;
+        }
+
+        if (len == 2
+            && ngx_de_name(&dir)[0] == '.'
+            && ngx_de_name(&dir)[0] == '.')
+        {
+            continue;
+        }
+
+        if (!(entry = ngx_array_push(&entries))) {
+            return ngx_http_autoindex_error(r, &dir, dname.data);
+        }
+
+        entry->name.len = len;        
+
+        if (!(entry->name.data = ngx_palloc(pool, len + 1))) {
+            return ngx_http_autoindex_error(r, &dir, dname.data);
+        }
+        ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1);
+
+        entry->dir = ngx_de_is_dir(&dir);
+        entry->mtime = ngx_de_mtime(&dir);
+        entry->size = ngx_de_size(&dir);
+    }
+
+    if (ngx_close_dir(&dir) == NGX_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+                      ngx_close_dir_n " \"%s\" failed", dname.data);
+    }
+
+    len = sizeof(title) - 1
+          + r->uri.len
+          + sizeof(header) - 1
+          + r->uri.len
+          + sizeof("</h1>") - 1
+          + sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1
+          + sizeof("</pre><hr>") - 1
+          + sizeof(tail) - 1;
+
+    entry = entries.elts;
+    for (i = 0; i < entries.nelts; i++) {
+        len += sizeof("<a href=\"") - 1
+               + 1                                          /* 1 is for "/" */
+               + entry[i].name.len
+               + sizeof("\">") - 1
+               + NGX_HTTP_AUTOINDEX_NAME_LEN
+               + sizeof("</a>") - 1
+               + 1
+               + sizeof("28-Sep-1970 12:00 ") - 1
+               + sizeof("1023G") - 1
+               + 2;
+    }
+
+    if (!(b = ngx_create_temp_buf(r->pool, len))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    if (entries.nelts > 1) {
+        ngx_qsort(entry, (size_t) entries.nelts,
+                  sizeof(ngx_http_autoindex_entry_t),
+                  ngx_http_autoindex_cmp_entries);
+    }
+
+    b->last = ngx_cpymem(b->last, title, sizeof(title) - 1);
+    b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len);
+    b->last = ngx_cpymem(b->last, header, sizeof(header) - 1);
+    b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len);
+    b->last = ngx_cpymem(b->last, "</h1>", sizeof("</h1>") - 1);
+
+    b->last = ngx_cpymem(b->last, "<hr><pre><a href=\"../\">../</a>" CRLF,
+                         sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1);
+
+    for (i = 0; i < entries.nelts; i++) {
+        b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1);
+        b->last = ngx_cpymem(b->last, entry[i].name.data, entry[i].name.len);
+
+        if (entry[i].dir) {
+            *b->last++ = '/';
+        }
+
+        *b->last++ = '"';
+        *b->last++ = '>';
+
+        b->last = ngx_cpystrn(b->last, entry[i].name.data,
+                              NGX_HTTP_AUTOINDEX_NAME_LEN + 1);
+
+        len = entry[i].name.len;
+
+        if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
+            b->last = ngx_cpymem(b->last - 3, "..&gt;</a>",
+                                 sizeof("..&gt;</a>") - 1);
+
+        } else {
+            if (entry[i].dir && NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) {
+                *b->last++ = '/';
+                len++;
+            }
+
+            b->last = ngx_cpymem(b->last, "</a>", sizeof("</a>") - 1);
+            ngx_memset(b->last, ' ', NGX_HTTP_AUTOINDEX_NAME_LEN - len);
+            b->last += NGX_HTTP_AUTOINDEX_NAME_LEN - len;
+        }
+
+        *b->last++ = ' ';
+
+        ngx_gmtime(entry[i].mtime, &tm);
+
+        b->last = ngx_sprintf(b->last, "%02d-%s-%d %02d:%02d ",
+                              tm.ngx_tm_mday,
+                              months[tm.ngx_tm_mon - 1],
+                              tm.ngx_tm_year,
+                              tm.ngx_tm_hour,
+                              tm.ngx_tm_min);
+
+        if (entry[i].dir) {
+            b->last = ngx_cpymem(b->last, "   -", sizeof("   -") - 1);
+
+        } else {
+            length = entry[i].size;
+
+            if (length > 999999999) {
+                size = (ngx_int_t) length / 1024 * 1024 * 1024;
+                if ((length % 1024 * 1024 * 1024)
+                                                > (1024 * 1024 * 1024 / 2 - 1))
+                {
+                    size++;
+                }
+                scale = 'G';
+
+            } else if (length > 999999) {
+                size = (ngx_int_t) length / 1024 * 1024;
+                if ((length % 1024 * 1024) > (1024 * 1024 / 2 - 1)) {
+                    size++;
+                }
+                scale = 'M';
+
+            } else if (length > 9999) {
+                size = (ngx_int_t) length / 1024;
+                if (length % 1024 > 511) {
+                    size++;
+                }
+                scale = 'K';
+
+            } else {
+                size = (ngx_int_t) length;
+                scale = ' ';
+            }
+
+            b->last = ngx_sprintf(b->last, "%4i", size);
+
+            if (scale != ' ') {
+                *b->last++ = scale;
+            }
+        }
+
+        *b->last++ = CR;
+        *b->last++ = LF;
+    }
+
+    b->last = ngx_cpymem(b->last, "</pre><hr>", sizeof("</pre><hr>") - 1);
+
+    b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1);
+
+    r->headers_out.status = NGX_HTTP_OK;
+    r->headers_out.content_length_n = b->last - b->pos;
+
+    r->headers_out.content_type = ngx_list_push(&r->headers_out.headers);
+    if (r->headers_out.content_type == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    r->headers_out.content_type->key.len = 0;
+    r->headers_out.content_type->key.data = NULL;
+    r->headers_out.content_type->value.len = sizeof("text/html") - 1;
+    r->headers_out.content_type->value.data = (u_char *) "text/html";
+
+    rc = ngx_http_send_header(r);
+
+    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+        return rc;
+    }
+
+    if (!r->main) {
+        b->last_buf = 1;
+    }
+
+    out.buf = b;
+    out.next = NULL;
+
+    return ngx_http_output_filter(r, &out);
+}
+
+
+static int ngx_http_autoindex_cmp_entries(const void *one, const void *two)
+{
+    ngx_http_autoindex_entry_t *first = (ngx_http_autoindex_entry_t *) one;
+    ngx_http_autoindex_entry_t *second = (ngx_http_autoindex_entry_t *) two;
+
+    if (first->dir && !second->dir) {
+        /* move the directories to the start */
+        return -1;
+    }
+
+    if (!first->dir && second->dir) {
+        /* move the directories to the start */
+        return 1;
+    }
+
+    return (int) ngx_strcmp(first->name.data, second->name.data);
+}
+
+
+#if 0
+
+static ngx_buf_t *ngx_http_autoindex_alloc(ngx_http_autoindex_ctx_t *ctx,
+                                           size_t size)
+{
+    ngx_chain_t  *cl;
+
+    if (ctx->buf) {
+
+        if ((size_t) (ctx->buf->end - ctx->buf->last) >= size) {
+            return ctx->buf;
+        }
+
+        ctx->size += ctx->buf->last - ctx->buf->pos;
+    }
+
+    if (!(ctx->buf = ngx_create_temp_buf(ctx->pool, ctx->alloc_size))) {
+        return NULL;
+    }
+
+    if (!(cl = ngx_alloc_chain_link(ctx->pool))) {
+        return NULL;
+    }
+
+    cl->buf = ctx->buf;
+    cl->next = NULL;
+
+    *ctx->last_out = cl;
+    ctx->last_out = &cl->next;
+
+    return ctx->buf;
+}
+
+#endif
+
+
+static ngx_int_t ngx_http_autoindex_error(ngx_http_request_t *r, ngx_dir_t *dir,
+                                          u_char *name)
+{
+    if (ngx_close_dir(dir) == NGX_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+                      ngx_close_dir_n " \"%s\" failed", name);
+    }
+
+    return NGX_HTTP_INTERNAL_SERVER_ERROR;
+}
+
+
+static ngx_int_t ngx_http_autoindex_init(ngx_cycle_t *cycle)
+{
+    ngx_http_handler_pt        *h;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
+
+    h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    *h = ngx_http_autoindex_handler;
+
+    return NGX_OK;
+}
+
+
+static void *ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_autoindex_loc_conf_t  *conf;
+
+    conf = ngx_palloc(cf->pool, sizeof(ngx_http_autoindex_loc_conf_t));
+    if (conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->enable = NGX_CONF_UNSET;
+
+    return conf;
+}
+
+
+static char *ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf,
+                                               void *parent, void *child)
+{
+    ngx_http_autoindex_loc_conf_t *prev = parent;
+    ngx_http_autoindex_loc_conf_t *conf = child;
+
+    ngx_conf_merge_value(conf->enable, prev->enable, 0);
+
+    return NGX_CONF_OK;
+}
--- a/src/http/modules/ngx_http_index_handler.c
+++ b/src/http/modules/ngx_http_index_handler.c
@@ -100,7 +100,7 @@ ngx_module_t  ngx_http_index_module = {
  * that path contains the usual file in place of the directory.
  */
 
-ngx_int_t ngx_http_index_handler(ngx_http_request_t *r)
+static ngx_int_t ngx_http_index_handler(ngx_http_request_t *r)
 {
     u_char                     *name;
     ngx_fd_t                    fd;
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -98,6 +98,13 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, preserve_host),
       NULL },
 
+    { ngx_string("proxy_set_x_url"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, set_x_url),
+      NULL },
+
     { ngx_string("proxy_set_x_real_ip"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -894,6 +901,7 @@ static void *ngx_http_proxy_create_loc_c
     conf->send_lowat = NGX_CONF_UNSET_SIZE;
 
     conf->preserve_host = NGX_CONF_UNSET;
+    conf->set_x_url = NGX_CONF_UNSET;
     conf->set_x_real_ip = NGX_CONF_UNSET;
     conf->add_x_forwarded_for = NGX_CONF_UNSET;
 
@@ -938,6 +946,7 @@ static char *ngx_http_proxy_merge_loc_co
     ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0);
 
     ngx_conf_merge_value(conf->preserve_host, prev->preserve_host, 0);
+    ngx_conf_merge_value(conf->set_x_url, prev->set_x_url, 0);
     ngx_conf_merge_value(conf->set_x_real_ip, prev->set_x_real_ip, 0);
     ngx_conf_merge_value(conf->add_x_forwarded_for,
                          prev->add_x_forwarded_for, 0);
@@ -1147,6 +1156,10 @@ static char *ngx_http_proxy_set_pass(ngx
 
         lcf->peers->number = i;
 
+        /* STUB */
+        lcf->peers->max_fails = 1;
+        lcf->peers->fail_timeout = 60;
+
         for (i = 0; h->h_addr_list[i] != NULL; i++) {
             lcf->peers->peers[i].host.data = host;
             lcf->peers->peers[i].host.len = lcf->upstream->host.len;
--- a/src/http/modules/proxy/ngx_http_proxy_handler.h
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.h
@@ -75,6 +75,7 @@ typedef struct {
     ngx_flag_t                       cyclic_temp_file;
     ngx_flag_t                       cache;
     ngx_flag_t                       preserve_host;
+    ngx_flag_t                       set_x_url;
     ngx_flag_t                       set_x_real_ip;
     ngx_flag_t                       add_x_forwarded_for;
     ngx_flag_t                       pass_server;
--- a/src/http/modules/proxy/ngx_http_proxy_upstream.c
+++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c
@@ -43,6 +43,7 @@ static char *upstream_header_errors[] = 
 
 static char  http_version[] = " HTTP/1.0" CRLF;
 static char  host_header[] = "Host: ";
+static char  x_url_header[] = "X-URL: http";
 static char  x_real_ip_header[] = "X-Real-IP: ";
 static char  x_forwarded_for_header[] = "X-Forwarded-For: ";
 static char  connection_close_header[] = "Connection: close" CRLF;
@@ -142,18 +143,36 @@ static ngx_chain_t *ngx_http_proxy_creat
     }
 
     len += uc->uri.len
-           + r->uri.len - uc->location->len + escape
-           + 1 + r->args.len                                 /* 1 is for "?" */
-           + sizeof(http_version) - 1
-           + sizeof(connection_close_header) - 1
-           + 2;                         /* 2 is for "\r\n" at the header end */
+        + r->uri.len - uc->location->len + escape
+        + 1 + r->args.len                                   /* 1 is for "?" */
+        + sizeof(http_version) - 1
+        + sizeof(connection_close_header) - 1
+        + 2;                           /* 2 is for "\r\n" at the header end */
+
+
+    if (p->lcf->set_x_url) {
+        len += sizeof(x_url_header) - 1
+            + 4                                          /* 4 is for "s://" */
+            + r->port_text->len
+            + r->unparsed_uri.len
+            + 2;                        /* 2 is for "\r\n" at the header end */
+
+        if (r->headers_in.host) {
+            len += r->headers_in.host_name_len;
+
+        } else {
+            len += r->server_name.len;
+        }
+
+    }
+
 
     if (p->lcf->preserve_host && r->headers_in.host) {
         len += sizeof(host_header) - 1
-               + r->headers_in.host_name_len
-               + 1                                           /* 1 is for ":" */
-               + uc->port_text.len
-               + 2;                                       /* 2 is for "\r\n" */
+            + r->headers_in.host_name_len
+            + 1                                              /* 1 is for ":" */
+            + uc->port_text.len
+            + 2;                                          /* 2 is for "\r\n" */
     } else {                                              /* 2 is for "\r\n" */
         len += sizeof(host_header) - 1 + uc->host_header.len + 2;
     }
@@ -167,10 +186,10 @@ static ngx_chain_t *ngx_http_proxy_creat
     if (p->lcf->add_x_forwarded_for) {
         if (r->headers_in.x_forwarded_for) {
             len += sizeof(x_forwarded_for_header) - 1
-                   + r->headers_in.x_forwarded_for->value.len
-                   + 2                                      /* 2 is ofr ", " */
-                   + INET_ADDRSTRLEN - 1
-                   + 2;                                   /* 2 is for "\r\n" */
+                + r->headers_in.x_forwarded_for->value.len
+                + 2                                         /* 2 is ofr ", " */
+                + INET_ADDRSTRLEN - 1
+                + 2;                                      /* 2 is for "\r\n" */
         } else {
             len += sizeof(x_forwarded_for_header) - 1 + INET_ADDRSTRLEN - 1 + 2;
                                                           /* 2 is for "\r\n" */
@@ -271,6 +290,39 @@ static ngx_chain_t *ngx_http_proxy_creat
     *(b->last++) = CR; *(b->last++) = LF;
 
 
+    /* the "X-URL" header */
+
+    if (p->lcf->set_x_url) {
+
+        b->last = ngx_cpymem(b->last, x_url_header,
+                             sizeof(x_url_header) - 1);
+
+#if (NGX_OPENSSL)
+
+        if (r->connection->ssl) {
+            *(b->last++) = 's';
+        }
+
+#endif
+
+        *(b->last++) = ':'; *(b->last++) = '/'; *(b->last++) = '/';
+
+        if (r->headers_in.host) {
+            b->last = ngx_cpymem(b->last, r->headers_in.host->value.data,
+                                 r->headers_in.host_name_len);
+        } else {
+            b->last = ngx_cpymem(b->last, r->server_name.data,
+                                 r->server_name.len);
+        }
+
+        b->last = ngx_cpymem(b->last, r->port_text->data, r->port_text->len);
+        b->last = ngx_cpymem(b->last, r->unparsed_uri.data,
+                             r->unparsed_uri.len);
+
+        *(b->last++) = CR; *(b->last++) = LF;
+    }
+
+
     /* the "X-Real-IP" header */
 
     if (p->lcf->set_x_real_ip) {
@@ -339,6 +391,14 @@ static ngx_chain_t *ngx_http_proxy_creat
             continue;
         }
 
+        if (&header[i] == r->headers_in.x_real_ip && p->lcf->set_x_real_ip) {
+            continue;
+        }
+
+        if (&header[i] == r->headers_in.x_url && p->lcf->set_x_url) {
+            continue;
+        }
+
         b->last = ngx_cpymem(b->last, header[i].key.data, header[i].key.len);
 
         *(b->last++) = ':'; *(b->last++) = ' ';
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1012,7 +1012,7 @@ static int ngx_cmp_locations(const void 
         return 1;
     }
 
-    return rc;
+    return (int) rc;
 }
 
 
--- a/src/http/ngx_http_header_filter.c
+++ b/src/http/ngx_http_header_filter.c
@@ -220,7 +220,7 @@ static ngx_int_t ngx_http_header_filter(
     {
         r->headers_out.location->key.len = 0;
         len += sizeof("Location: http://") - 1
-               + r->server_name->len + r->headers_out.location->value.len + 2;
+               + r->server_name.len + r->headers_out.location->value.len + 2;
 
         if (r->port != 80) {
             len += r->port_text->len;
@@ -356,8 +356,8 @@ static ngx_int_t ngx_http_header_filter(
         p = b->last + sizeof("Location: ") - 1;
         b->last = ngx_cpymem(b->last, "Location: http://",
                              sizeof("Location: http://") - 1);
-        b->last = ngx_cpymem(b->last, r->server_name->data,
-                             r->server_name->len);
+        b->last = ngx_cpymem(b->last, r->server_name.data,
+                             r->server_name.len);
         if (r->port != 80) {
             b->last = ngx_cpymem(b->last, r->port_text->data,
                                  r->port_text->len);
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -84,6 +84,8 @@ ngx_http_header_t  ngx_http_headers_in[]
 #if (NGX_HTTP_PROXY)
     { ngx_string("X-Forwarded-For"),
                            offsetof(ngx_http_headers_in_t, x_forwarded_for) },
+    { ngx_string("X-Real-IP"), offsetof(ngx_http_headers_in_t, x_real_ip) },
+    { ngx_string("X-URL"), offsetof(ngx_http_headers_in_t, x_url) },
 #endif
     
     { ngx_null_string, 0 }
@@ -351,7 +353,7 @@ static void ngx_http_init_request(ngx_ev
 #endif
 
     server_name = cscf->server_names.elts;
-    r->server_name = &server_name->name;
+    r->server_name = server_name->name;
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
     c->log->file = clcf->err_log->file;
@@ -1122,7 +1124,14 @@ static ngx_int_t ngx_http_process_reques
 
             r->srv_conf = name[i].core_srv_conf->ctx->srv_conf;
             r->loc_conf = name[i].core_srv_conf->ctx->loc_conf;
-            r->server_name = &name[i].name;
+
+            if (name[i].wildcard) {
+                r->server_name.len = r->headers_in.host_name_len;
+                r->server_name.data = r->headers_in.host->value.data;
+
+            } else {
+                r->server_name = name[i].name;
+            }
 
             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
             r->connection->log->file = clcf->err_log->file;
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -146,6 +146,8 @@ typedef struct {
 
 #if (NGX_HTTP_PROXY)
     ngx_table_elt_t  *x_forwarded_for;
+    ngx_table_elt_t  *x_real_ip;
+    ngx_table_elt_t  *x_url;
 #endif
 
     ngx_array_t       cookies;
@@ -283,7 +285,7 @@ struct ngx_http_request_s {
     uint32_t             in_addr;
     ngx_uint_t           port;
     ngx_str_t           *port_text;    /* ":80" */
-    ngx_str_t           *server_name;
+    ngx_str_t            server_name;
     ngx_array_t         *virtual_names;
 
     ngx_uint_t           phase;
--- a/src/os/unix/ngx_errno.c
+++ b/src/os/unix/ngx_errno.c
@@ -8,7 +8,7 @@
 #include <ngx_core.h>
 
 
-#if (HAVE_STRERROR_R)
+#if (NGX_STRERROR_R)
 
 ngx_int_t ngx_strerror_r(int err, char *errstr, size_t size)
 {
@@ -31,7 +31,7 @@ ngx_int_t ngx_strerror_r(int err, char *
     return len;
 }
 
-#elif (HAVE_GNU_STRERROR_R)
+#elif (NGX_GNU_STRERROR_R)
 
 /* Linux strerror_r() */
 
--- a/src/os/unix/ngx_errno.h
+++ b/src/os/unix/ngx_errno.h
@@ -51,6 +51,8 @@ ngx_int_t ngx_strerror_r(int err, char *
 
 #else
 
+/* Solaris has threads-safe strerror() */
+
 #define ngx_strerror_r(err, errstr, size)  \
              (char *) ngx_cpystrn(errstr, strerror(err), size) - (errstr)
 
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -15,7 +15,7 @@ ssize_t ngx_read_file(ngx_file_t *file, 
     ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
                    "read: %d, %X, %d, " OFF_T_FMT, file->fd, buf, size, offset);
 
-#if (HAVE_PREAD)
+#if (NGX_PREAD)
 
     n = pread(file->fd, buf, size, offset);
 
@@ -57,7 +57,7 @@ ssize_t ngx_write_file(ngx_file_t *file,
 {
     ssize_t n;
 
-#if (HAVE_PWRITE)
+#if (NGX_PWRITE)
 
     n = pwrite(file->fd, buf, size, offset);
 
@@ -206,7 +206,7 @@ int ngx_open_dir(ngx_str_t *name, ngx_di
         return NGX_ERROR;
     }
 
-    dir->info_valid = 0;
+    dir->valid_info = 0;
 
     return NGX_OK;
 }
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -98,7 +98,7 @@ int ngx_open_dir(ngx_str_t *name, ngx_di
 #define ngx_delete_dir_n         "rmdir()"
 
 
-#define ngx_de_name(dir)         (dir)->de->d_name
+#define ngx_de_name(dir)         ((u_char *) (dir)->de->d_name)
 #if (NGX_FREEBSD)
 #define ngx_de_namelen(dir)      (dir)->de->d_namlen
 #else
--- a/src/os/unix/ngx_types.h
+++ b/src/os/unix/ngx_types.h
@@ -19,7 +19,8 @@ typedef struct {
     DIR              *dir;
     struct dirent    *de;
     struct stat       info;
-    unsigned          info_valid;
+
+    ngx_uint_t        valid_info:1;  /* unsigned  valid_info:1; */
 } ngx_dir_t;