# HG changeset patch # User Igor Sysoev # Date 1098648000 -14400 # Node ID 80ba094c6b3e4a8cae0fd8de6fabc967437e39c8 # Parent 985c56ebe724b0ad13d5c8bf61043f1d7c106641 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. diff --git a/CHANGES b/CHANGES --- 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. diff --git a/CHANGES.ru b/CHANGES.ru --- 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. diff --git a/auto/modules b/auto/modules --- 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 diff --git a/auto/options b/auto/options --- 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 ;; diff --git a/auto/sources b/auto/sources --- 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 diff --git a/auto/summary b/auto/summary --- 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" diff --git a/auto/threads b/auto/threads --- 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 diff --git a/configure b/configure --- 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 diff --git a/src/core/nginx.h b/src/core/nginx.h --- 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" diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h --- 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 diff --git a/src/core/ngx_garbage_collector.c b/src/core/ngx_garbage_collector.c --- 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); diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- 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++; diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h --- 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; */ diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c --- 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); diff --git a/src/http/modules/ngx_http_autoindex_handler.c b/src/http/modules/ngx_http_autoindex_handler.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_autoindex_handler.c @@ -0,0 +1,560 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +#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[] = +"" CRLF +"Index of " +; + + +static u_char header[] = +"" CRLF +"" CRLF +"

Index of " +; + +static u_char tail[] = +"" CRLF +"" 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("

") - 1 + + sizeof("
../" CRLF) - 1
+          + sizeof("

") - 1 + + sizeof(tail) - 1; + + entry = entries.elts; + for (i = 0; i < entries.nelts; i++) { + len += sizeof("") - 1 + + NGX_HTTP_AUTOINDEX_NAME_LEN + + sizeof("") - 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, "", sizeof("") - 1); + + b->last = ngx_cpymem(b->last, "
../" CRLF,
+                         sizeof("
../" CRLF) - 1);
+
+    for (i = 0; i < entries.nelts; i++) {
+        b->last = ngx_cpymem(b->last, "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, "..>",
+                                 sizeof("..>") - 1);
+
+        } else {
+            if (entry[i].dir && NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) {
+                *b->last++ = '/';
+                len++;
+            }
+
+            b->last = ngx_cpymem(b->last, "", sizeof("") - 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, "

", sizeof("

") - 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; +} diff --git a/src/http/modules/ngx_http_index_handler.c b/src/http/modules/ngx_http_index_handler.c --- 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; diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.c b/src/http/modules/proxy/ngx_http_proxy_handler.c --- 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; diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.h b/src/http/modules/proxy/ngx_http_proxy_handler.h --- 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; diff --git a/src/http/modules/proxy/ngx_http_proxy_upstream.c b/src/http/modules/proxy/ngx_http_proxy_upstream.c --- 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++) = ' '; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- 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; } diff --git a/src/http/ngx_http_header_filter.c b/src/http/ngx_http_header_filter.c --- 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); diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- 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; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- 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; diff --git a/src/os/unix/ngx_errno.c b/src/os/unix/ngx_errno.c --- a/src/os/unix/ngx_errno.c +++ b/src/os/unix/ngx_errno.c @@ -8,7 +8,7 @@ #include -#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() */ diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h --- 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) diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c --- 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; } diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h --- 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 diff --git a/src/os/unix/ngx_types.h b/src/os/unix/ngx_types.h --- 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;