# HG changeset patch # User Igor Sysoev # Date 1220817600 -14400 # Node ID 79c5df00501e08b14b9457873e691c74059e7519 # Parent 2993e60bc4e0652218909284ef640b03eab6672d nginx 0.7.15 *) Feature: the ngx_http_random_index_module. *) Feature: the "directio" directive has been optimized for file requests starting from arbitrary position. *) Feature: the "directio" directive turns off sendfile if it is necessary. *) Feature: now nginx allows underscores in a client request header line names. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,18 @@ +Changes with nginx 0.7.15 08 Sep 2008 + + *) Feature: the ngx_http_random_index_module. + + *) Feature: the "directio" directive has been optimized for file + requests starting from arbitrary position. + + *) Feature: the "directio" directive turns off sendfile if it is + necessary. + + *) Feature: now nginx allows underscores in a client request header + line names. + + Changes with nginx 0.7.14 01 Sep 2008 *) Change: now the ssl_certificate and ssl_certificate_key directives diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,18 @@ +Изменения в nginx 0.7.15 08.09.2008 + + *) Добавление: модуль ngx_http_random_index_module. + + *) Добавление: директива directio оптимизирована для запросов файлов, + начинающихся с произвольной позиции. + + *) Добавление: директива directio при необходимости запрещает + использование sendfile. + + *) Добавление: теперь nginx разрешает подчёркивания в именах строк в + заголовке запроса клиента. + + Изменения в nginx 0.7.14 01.09.2008 *) Изменение: теперь директивы ssl_certificate и ssl_certificate_key не diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -81,6 +81,7 @@ fi # ngx_http_dav_module # ngx_http_autoindex_module # ngx_http_index_module +# ngx_http_random_index_module # # ngx_http_access_module # ngx_http_realip_module @@ -177,6 +178,12 @@ fi HTTP_MODULES="$HTTP_MODULES $HTTP_INDEX_MODULE" +if [ $HTTP_RANDOM_INDEX = YES ]; then + have=NGX_HTTP_RANDOM_INDEX . auto/have + HTTP_MODULES="$HTTP_MODULES $HTTP_RANDOM_INDEX_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_RANDOM_INDEX_SRCS" +fi + if [ $HTTP_AUTH_BASIC = YES ]; then have=NGX_HTTP_AUTH_BASIC . auto/have have=NGX_CRYPT . auto/have diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -64,6 +64,7 @@ HTTP_ACCESS=YES HTTP_AUTH_BASIC=YES HTTP_USERID=YES HTTP_AUTOINDEX=YES +HTTP_RANDOM_INDEX=NO HTTP_STATUS=NO HTTP_GEO=YES HTTP_MAP=YES @@ -171,6 +172,7 @@ do --with-http_dav_module) HTTP_DAV=YES ;; --with-http_flv_module) HTTP_FLV=YES ;; --with-http_gzip_static_module) HTTP_GZIP_STATIC=YES ;; + --with-http_random_index_module) HTTP_RANDOM_INDEX=YES ;; --without-http_charset_module) HTTP_CHARSET=NO ;; --without-http_gzip_module) HTTP_GZIP=NO ;; @@ -287,6 +289,7 @@ cat << END --with-http_dav_module enable ngx_http_dav_module --with-http_flv_module enable ngx_http_flv_module --with-http_gzip_static_module enable ngx_http_gzip_static_module + --with-http_random_index_module enable ngx_http_random_index_module --with-http_stub_status_module enable ngx_http_stub_status_module --without-http_charset_module disable ngx_http_charset_module diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -131,7 +131,6 @@ UNIX_INCS="$CORE_INCS $EVENT_INCS src/os UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \ src/os/unix/ngx_time.h \ - src/os/unix/ngx_types.h \ src/os/unix/ngx_errno.h \ src/os/unix/ngx_alloc.h \ src/os/unix/ngx_files.h \ @@ -208,7 +207,6 @@ WIN32_INCS="$CORE_INCS $EVENT_INCS src/o WIN32_DEPS="$CORE_DEPS $EVENT_DEPS \ src/os/win32/ngx_win32_config.h \ src/os/win32/ngx_time.h \ - src/os/win32/ngx_types.h \ src/os/win32/ngx_errno.h \ src/os/win32/ngx_alloc.h \ src/os/win32/ngx_files.h \ @@ -368,6 +366,10 @@ HTTP_AUTOINDEX_MODULE=ngx_http_autoindex HTTP_AUTOINDEX_SRCS=src/http/modules/ngx_http_autoindex_module.c +HTTP_RANDOM_INDEX_MODULE=ngx_http_random_index_module +HTTP_RANDOM_INDEX_SRCS=src/http/modules/ngx_http_random_index_module.c + + HTTP_STATUS_MODULE=ngx_http_status_module HTTP_STATUS_SRCS=src/http/modules/ngx_http_status_module.c diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -229,3 +229,23 @@ ngx_feature_path= ngx_feature_libs= ngx_feature_test="struct tm tm; tm.tm_gmtoff = 0" . auto/feature + + +ngx_feature="struct dirent.d_namlen" +ngx_feature_name="NGX_HAVE_D_NAMLEN" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="struct dirent dir; dir.d_namlen = 0" +. auto/feature + + +ngx_feature="struct dirent.d_type" +ngx_feature_name="NGX_HAVE_D_TYPE" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="struct dirent dir; dir.d_type = DT_REG" +. auto/feature diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -6,7 +6,6 @@ #include #include -#include #include 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_VERSION "0.7.14" +#define NGINX_VERSION "0.7.15" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -78,6 +78,7 @@ typedef struct { ngx_chain_t *busy; unsigned sendfile; + unsigned directio; unsigned need_in_memory; unsigned need_in_temp; diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -40,11 +40,11 @@ typedef void (*ngx_connection_handler_pt #include #include #include -#include +#include +#include #include #include #include -#include #include #include #include @@ -55,7 +55,6 @@ typedef void (*ngx_connection_handler_pt #include #include #include -#include #include #include #if (NGX_PCRE) 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,8 @@ struct ngx_file_s { ngx_log_t *log; - ngx_uint_t valid_info; /* unsigned valid_info:1; */ + unsigned valid_info:1; + unsigned directio:1; }; #define NGX_MAX_PATH_LEVEL 3 diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -502,6 +502,9 @@ ngx_open_and_stat_file(u_char *name, ngx if (ngx_directio(fd) == -1) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_directio_n " \"%s\" failed", name); + + } else { + of->is_directio = 1; } } } diff --git a/src/core/ngx_open_file_cache.h b/src/core/ngx_open_file_cache.h --- a/src/core/ngx_open_file_cache.h +++ b/src/core/ngx_open_file_cache.h @@ -33,6 +33,7 @@ typedef struct { unsigned is_file:1; unsigned is_link:1; unsigned is_exec:1; + unsigned is_directio:1; } ngx_open_file_info_t; diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -18,21 +18,21 @@ static ngx_inline ngx_int_t - ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); + ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in); -static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, - ngx_uint_t sendfile); +static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, + off_t bsize); +static ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, + off_t bsize); +static ngx_int_t ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx); ngx_int_t ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) { off_t bsize; - size_t size; ngx_int_t rc, last; - ngx_uint_t recycled; - ngx_buf_t *b; ngx_chain_t *cl, *out, **last_out; if (ctx->in == NULL && ctx->busy == NULL) { @@ -51,7 +51,7 @@ ngx_output_chain(ngx_output_chain_ctx_t #if (NGX_SENDFILE_LIMIT) && !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT) #endif - && !ngx_output_chain_need_to_copy(ctx, in->buf)) + && ngx_output_chain_as_is(ctx, in->buf)) { return ctx->output_filter(ctx->filter_ctx, in); } @@ -75,7 +75,7 @@ ngx_output_chain(ngx_output_chain_ctx_t /* * cycle while there are the ctx->in bufs - * or there are the free output bufs to copy in + * and there are the free output bufs to copy in */ bsize = ngx_buf_size(ctx->in->buf); @@ -102,7 +102,7 @@ ngx_output_chain(ngx_output_chain_ctx_t continue; } - if (!ngx_output_chain_need_to_copy(ctx, ctx->in->buf)) { + if (ngx_output_chain_as_is(ctx, ctx->in->buf)) { /* move the chain link to the output chain */ @@ -118,79 +118,35 @@ ngx_output_chain(ngx_output_chain_ctx_t if (ctx->buf == NULL) { - /* get the free buf */ + rc = ngx_output_chain_align_file_buf(ctx, bsize); - if (ctx->free) { - cl = ctx->free; - ctx->buf = cl->buf; - ctx->free = cl->next; - ngx_free_chain(ctx->pool, cl); - - } else if (out || ctx->allocated == ctx->bufs.num) { + if (rc == NGX_ERROR) { + return NGX_ERROR; + } - break; - - } else { + if (rc != NGX_OK) { - size = ctx->bufs.size; - recycled = 1; + if (ctx->free) { - if (ctx->in->buf->last_in_chain) { - - if (bsize < (off_t) ctx->bufs.size) { + /* get the free buf */ - /* - * allocate small temp buf for the small last buf - * or its small last part - */ + cl = ctx->free; + ctx->buf = cl->buf; + ctx->free = cl->next; - size = (size_t) bsize; - recycled = 0; + ngx_free_chain(ctx->pool, cl); - } else if (ctx->bufs.num == 1 - && (bsize < (off_t) (ctx->bufs.size - + (ctx->bufs.size >> 2)))) - { - /* - * allocate a temp buf that equals - * to the last buf if the last buf size is lesser - * than 1.25 of bufs.size and a temp buf is single - */ + } else if (out || ctx->allocated == ctx->bufs.num) { - size = (size_t) bsize; - recycled = 0; - } - } + break; - b = ngx_calloc_buf(ctx->pool); - if (b == NULL) { + } else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) { return NGX_ERROR; } - - /* - * allocate block aligned to a disk sector size - * to enable O_DIRECT - */ - - b->start = ngx_pmemalign(ctx->pool, size, 512); - if (b->start == NULL) { - return NGX_ERROR; - } - - b->pos = b->start; - b->last = b->start; - b->end = b->last + size; - b->temporary = 1; - b->tag = ctx->tag; - b->recycled = recycled; - - ctx->buf = b; - ctx->allocated++; } } - rc = ngx_output_chain_copy_buf(ctx->buf, ctx->in->buf, - ctx->sendfile); + rc = ngx_output_chain_copy_buf(ctx); if (rc == NGX_ERROR) { return rc; @@ -244,11 +200,15 @@ ngx_output_chain(ngx_output_chain_ctx_t static ngx_inline ngx_int_t -ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) +ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) { ngx_uint_t sendfile; if (ngx_buf_special(buf)) { + return 1; + } + + if (buf->in_file && buf->file->directio) { return 0; } @@ -265,21 +225,21 @@ ngx_output_chain_need_to_copy(ngx_output if (!sendfile) { if (!ngx_buf_in_memory(buf)) { - return 1; + return 0; } buf->in_file = 0; } if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) { - return 1; + return 0; } if (ctx->need_in_temp && (buf->memory || buf->mmap)) { - return 1; + return 0; } - return 0; + return 1; } @@ -313,6 +273,8 @@ ngx_output_chain_add_copy(ngx_pool_t *po && buf->file_pos < NGX_SENDFILE_LIMIT && buf->file_last > NGX_SENDFILE_LIMIT) { + /* split a file buf on two bufs by the sendfile limit */ + b = ngx_calloc_buf(pool); if (b == NULL) { return NGX_ERROR; @@ -352,10 +314,137 @@ ngx_output_chain_add_copy(ngx_pool_t *po static ngx_int_t -ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, ngx_uint_t sendfile) +ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) +{ + size_t size; + ngx_buf_t *in; + + in = ctx->in->buf; + + if (in->file == NULL || !in->file->directio) { + return NGX_DECLINED; + } + + ctx->directio = 1; + + size = (size_t) (in->file_pos - (in->file_pos & ~511)); + + if (size == 0) { + + if (bsize >= ctx->bufs.size) { + return NGX_DECLINED; + } + + size = (size_t) bsize; + + } else { + size = 512 - size; + + if (size > bsize) { + size = (size_t) bsize; + } + } + + ctx->buf = ngx_create_temp_buf(ctx->pool, size); + if (ctx->buf == NULL) { + return NGX_ERROR; + } + + /* + * we do not set ctx->buf->tag, because we do not want + * to reuse the buf via ctx->free list + */ + + return NGX_OK; +} + + +static ngx_int_t +ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) { - off_t size; - ssize_t n; + size_t size; + ngx_buf_t *b, *in; + ngx_uint_t recycled; + + in = ctx->in->buf; + size = ctx->bufs.size; + recycled = 1; + + if (in->last_in_chain) { + + if (bsize < (off_t) size) { + + /* + * allocate a small temp buf for a small last buf + * or its small last part + */ + + size = (size_t) bsize; + recycled = 0; + + } else if (!ctx->directio + && ctx->bufs.num == 1 + && (bsize < (off_t) (size + size / 4))) + { + /* + * allocate a temp buf that equals to a last buf, + * if there is no directio, the last buf size is lesser + * than 1.25 of bufs.size and the temp buf is single + */ + + size = (size_t) bsize; + recycled = 0; + } + } + + b = ngx_calloc_buf(ctx->pool); + if (b == NULL) { + return NGX_ERROR; + } + + if (ctx->directio) { + + /* + * allocate block aligned to a disk sector size to enable + * userland buffer direct usage conjunctly with directio + */ + + b->start = ngx_pmemalign(ctx->pool, size, 512); + if (b->start == NULL) { + return NGX_ERROR; + } + + } else { + b->start = ngx_palloc(ctx->pool, size); + if (b->start == NULL) { + return NGX_ERROR; + } + } + + b->pos = b->start; + b->last = b->start; + b->end = b->last + size; + b->temporary = 1; + b->tag = ctx->tag; + b->recycled = recycled; + + ctx->buf = b; + ctx->allocated++; + + return NGX_OK; +} + + +static ngx_int_t +ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx) +{ + off_t size; + ssize_t n; + ngx_buf_t *src, *dst; + ngx_uint_t sendfile; + + src = ctx->in->buf; + dst = ctx->buf; size = ngx_buf_size(src); @@ -363,6 +452,8 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst size = dst->end - dst->pos; } + sendfile = ctx->sendfile & !ctx->directio; + #if (NGX_SENDFILE_LIMIT) if (src->in_file && src->file_pos >= NGX_SENDFILE_LIMIT) { @@ -413,7 +504,7 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst #endif if (n != size) { - ngx_log_error(NGX_LOG_ALERT, src->file->log, 0, + ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, ngx_read_file_n " read only %z of %O from file", n, size); if (n == 0) { diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -7,7 +7,6 @@ #include #include #include -#include typedef struct { diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c --- a/src/http/modules/ngx_http_flv_module.c +++ b/src/http/modules/ngx_http_flv_module.c @@ -244,6 +244,7 @@ ngx_http_flv_handler(ngx_http_request_t b->file->fd = of.fd; b->file->name = path; b->file->log = log; + b->file->directio = of.is_directio; out[1].buf = b; out[1].next = NULL; diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c --- a/src/http/modules/ngx_http_gzip_static_module.c +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -235,6 +235,7 @@ ngx_http_gzip_static_handler(ngx_http_re b->file->fd = of.fd; b->file->name = path; b->file->log = log; + b->file->directio = of.is_directio; out.buf = b; out.next = NULL; diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c --- a/src/http/modules/ngx_http_log_module.c +++ b/src/http/modules/ngx_http_log_module.c @@ -7,7 +7,6 @@ #include #include #include -#include typedef struct ngx_http_log_op_s ngx_http_log_op_t; diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -6,7 +6,6 @@ #include #include -#include #include diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -6,7 +6,6 @@ #include #include -#include #include diff --git a/src/http/modules/ngx_http_random_index_module.c b/src/http/modules/ngx_http_random_index_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_random_index_module.c @@ -0,0 +1,321 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct { + ngx_flag_t enable; +} ngx_http_random_index_loc_conf_t; + + +#define NGX_HTTP_RANDOM_INDEX_PREALLOCATE 50 + + +static ngx_int_t ngx_http_random_index_error(ngx_http_request_t *r, + ngx_dir_t *dir, ngx_str_t *name); +static ngx_int_t ngx_http_random_index_init(ngx_conf_t *cf); +static void *ngx_http_random_index_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_random_index_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); + + +static ngx_command_t ngx_http_random_index_commands[] = { + + { ngx_string("random_index"), + NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_random_index_loc_conf_t, enable), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_random_index_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_random_index_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_random_index_create_loc_conf, /* create location configration */ + ngx_http_random_index_merge_loc_conf /* merge location configration */ +}; + + +ngx_module_t ngx_http_random_index_module = { + NGX_MODULE_V1, + &ngx_http_random_index_module_ctx, /* module context */ + ngx_http_random_index_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_http_random_index_handler(ngx_http_request_t *r) +{ + u_char *last, *filename; + size_t len, allocated, root; + ngx_err_t err; + ngx_int_t rc; + ngx_str_t path, uri, *name; + ngx_dir_t dir; + ngx_uint_t n, level; + ngx_array_t names; + ngx_http_random_index_loc_conf_t *rlcf; + + if (r->uri.data[r->uri.len - 1] != '/') { + return NGX_DECLINED; + } + + /* TODO: Win32 */ + if (r->zero_in_uri) { + return NGX_DECLINED; + } + + if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { + return NGX_DECLINED; + } + + rlcf = ngx_http_get_module_loc_conf(r, ngx_http_random_index_module); + + if (!rlcf->enable) { + return NGX_DECLINED; + } + +#if (NGX_HAVE_D_TYPE) + len = NGX_DIR_MASK_LEN; +#else + len = NGX_HTTP_RANDOM_INDEX_PREALLOCATE; +#endif + + last = ngx_http_map_uri_to_path(r, &path, &root, len); + if (last == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + allocated = path.len; + + path.len = last - path.data - 1; + path.data[path.len] = '\0'; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http random index: \"%s\"", path.data); + + if (ngx_open_dir(&path, &dir) == NGX_ERROR) { + err = ngx_errno; + + if (err == NGX_ENOENT + || err == NGX_ENOTDIR + || err == NGX_ENAMETOOLONG) + { + 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", path.data); + + return rc; + } + + if (ngx_array_init(&names, r->pool, 32, sizeof(ngx_str_t)) != NGX_OK) { + return ngx_http_random_index_error(r, &dir, &path); + } + + filename = path.data; + filename[path.len] = '/'; + + for ( ;; ) { + ngx_set_errno(0); + + if (ngx_read_dir(&dir) == NGX_ERROR) { + err = ngx_errno; + + if (err != NGX_ENOMOREFILES) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, + ngx_read_dir_n " \"%V\" failed", &path); + return ngx_http_random_index_error(r, &dir, &path); + } + + break; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http random index file: \"%s\"", ngx_de_name(&dir)); + + if (ngx_de_name(&dir)[0] == '.') { + continue; + } + + len = ngx_de_namelen(&dir); + + if (!dir.valid_type) { + + /* 1 byte for '/' and 1 byte for terminating '\0' */ + + if (path.len + 1 + len + 1 > allocated) { + allocated = path.len + 1 + len + 1 + + NGX_HTTP_RANDOM_INDEX_PREALLOCATE; + + filename = ngx_pnalloc(r->pool, allocated); + if (filename == NULL) { + return ngx_http_random_index_error(r, &dir, &path); + } + + last = ngx_cpystrn(filename, path.data, path.len + 1); + *last++ = '/'; + } + + ngx_cpystrn(last, ngx_de_name(&dir), len + 1); + + if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { + err = ngx_errno; + + if (err != NGX_ENOENT) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, + ngx_de_info_n " \"%s\" failed", filename); + return ngx_http_random_index_error(r, &dir, &path); + } + + if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, + ngx_de_link_info_n " \"%s\" failed", + filename); + return ngx_http_random_index_error(r, &dir, &path); + } + } + } + + if (!ngx_de_is_file(&dir)) { + continue; + } + + name = ngx_array_push(&names); + if (name == NULL) { + return ngx_http_random_index_error(r, &dir, &path); + } + + name->len = len; + + name->data = ngx_pnalloc(r->pool, len); + if (name->data == NULL) { + return ngx_http_random_index_error(r, &dir, &path); + } + + ngx_memcpy(name->data, ngx_de_name(&dir), len); + } + + if (ngx_close_dir(&dir) == NGX_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_close_dir_n " \"%s\" failed", &path); + } + + n = names.nelts; + + if (n == 0) { + return NGX_DECLINED; + } + + name = names.elts; + + n = (ngx_uint_t) (((uint64_t) ngx_random() * n) / 0x80000000); + + uri.len = r->uri.len + name[n].len; + + uri.data = ngx_pnalloc(r->pool, uri.len); + if (uri.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + last = ngx_copy(uri.data, r->uri.data, r->uri.len); + ngx_memcpy(last, name[n].data, name[n].len); + + return ngx_http_internal_redirect(r, &uri, &r->args); +} + + +static ngx_int_t +ngx_http_random_index_error(ngx_http_request_t *r, ngx_dir_t *dir, + ngx_str_t *name) +{ + if (ngx_close_dir(dir) == NGX_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_close_dir_n " \"%V\" failed", name); + } + + return NGX_HTTP_INTERNAL_SERVER_ERROR; +} + + +static void * +ngx_http_random_index_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_random_index_loc_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_random_index_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + conf->enable = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_http_random_index_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_random_index_loc_conf_t *prev = parent; + ngx_http_random_index_loc_conf_t *conf = child; + + ngx_conf_merge_value(conf->enable, prev->enable, 0); + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_random_index_init(ngx_conf_t *cf) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_random_index_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -251,6 +251,7 @@ ngx_http_static_handler(ngx_http_request b->file->fd = of.fd; b->file->name = path; b->file->log = log; + b->file->directio = of.is_directio; out.buf = b; out.next = NULL; diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.7.14'; +our $VERSION = '0.7.15'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -681,6 +681,7 @@ sendfile(r, filename, offset = -1, bytes b->file->fd = of.fd; b->file->log = r->connection->log; + b->file->directio = of.is_directio; (void) ngx_http_perl_output(r, b); diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -6,7 +6,6 @@ #include #include -#include #include 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 @@ -6,9 +6,7 @@ #include #include -#include #include -#include typedef struct { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -8,8 +8,8 @@ #define _NGX_HTTP_CORE_H_INCLUDED_ -#include -#include +#include +#include #include diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -720,7 +720,7 @@ ngx_http_parse_header_line(ngx_http_requ static u_char lowcase[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0" - "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" + "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0_" "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" diff --git a/src/http/ngx_http_parse_time.c b/src/http/ngx_http_parse_time.c --- a/src/http/ngx_http_parse_time.c +++ b/src/http/ngx_http_parse_time.c @@ -6,7 +6,6 @@ #include #include -#include static int mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 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 @@ -6,7 +6,6 @@ #include #include -#include #include diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -6,7 +6,6 @@ #include #include -#include #include diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -6,7 +6,6 @@ #include #include -#include #include #include diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h --- a/src/http/ngx_http_variables.h +++ b/src/http/ngx_http_variables.h @@ -10,7 +10,6 @@ #include #include -#include #include diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -6,7 +6,6 @@ #include #include -#include #include 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 @@ -249,12 +249,33 @@ ngx_open_dir(ngx_str_t *name, ngx_dir_t } dir->valid_info = 0; +#if (NGX_HAVE_D_TYPE) + dir->valid_type = 1; +#else + dir->valid_type = 0; +#endif return NGX_OK; } ngx_int_t +ngx_read_dir(ngx_dir_t *dir) +{ + dir->de = readdir(dir->dir); + + if (dir->de) { +#if (NGX_HAVE_D_TYPE) + dir->type = dir->de->d_type; +#endif + return NGX_OK; + } + + return NGX_ERROR; +} + + +ngx_int_t ngx_open_glob(ngx_glob_t *gl) { int n; 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 @@ -12,6 +12,31 @@ #include +typedef int ngx_fd_t; +typedef struct stat ngx_file_info_t; +typedef ino_t ngx_file_uniq_t; + + +typedef struct { + DIR *dir; + struct dirent *de; + struct stat info; + + unsigned type:8; + unsigned valid_info:1; + unsigned valid_type:1; +} ngx_dir_t; + + +typedef struct { + size_t n; + glob_t pglob; + u_char *pattern; + ngx_log_t *log; + ngx_uint_t test; +} ngx_glob_t; + + #define NGX_INVALID_FILE -1 #define NGX_FILE_ERROR -1 @@ -135,8 +160,7 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, #define ngx_close_dir_n "closedir()" -#define ngx_read_dir(d) \ - (((d)->de = readdir((d)->dir)) ? NGX_OK : NGX_ERROR) +ngx_int_t ngx_read_dir(ngx_dir_t *dir); #define ngx_read_dir_n "readdir()" @@ -152,7 +176,7 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, #define ngx_de_name(dir) ((u_char *) (dir)->de->d_name) -#if (NGX_FREEBSD) +#if (NGX_HAVE_D_NAMLEN) #define ngx_de_namelen(dir) (dir)->de->d_namlen #else #define ngx_de_namelen(dir) ngx_strlen((dir)->de->d_name) @@ -161,23 +185,26 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, #define ngx_de_info_n "stat()" #define ngx_de_link_info(name, dir) lstat((const char *) name, &(dir)->info) #define ngx_de_link_info_n "lstat()" + +#if (NGX_HAVE_D_TYPE) + +#define ngx_de_is_dir(dir) ((dir)->type == DT_DIR) +#define ngx_de_is_file(dir) ((dir)->type == DT_REG) +#define ngx_de_is_link(dir) ((dir)->type == DT_LINK) + +#else + #define ngx_de_is_dir(dir) (S_ISDIR((dir)->info.st_mode)) #define ngx_de_is_file(dir) (S_ISREG((dir)->info.st_mode)) #define ngx_de_is_link(dir) (S_ISLNK((dir)->info.st_mode)) + +#endif + #define ngx_de_access(dir) (((dir)->info.st_mode) & 0777) #define ngx_de_size(dir) (dir)->info.st_size #define ngx_de_mtime(dir) (dir)->info.st_mtime -typedef struct { - size_t n; - glob_t pglob; - u_char *pattern; - ngx_log_t *log; - ngx_uint_t test; -} ngx_glob_t; - - ngx_int_t ngx_open_glob(ngx_glob_t *gl); #define ngx_open_glob_n "glob()" ngx_int_t ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name); diff --git a/src/os/unix/ngx_types.h b/src/os/unix/ngx_types.h deleted file mode 100644 --- a/src/os/unix/ngx_types.h +++ /dev/null @@ -1,27 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#ifndef _NGX_TYPES_H_INCLUDED_ -#define _NGX_TYPES_H_INCLUDED_ - - -#include - - -typedef int ngx_fd_t; -typedef struct stat ngx_file_info_t; -typedef ino_t ngx_file_uniq_t; - -typedef struct { - DIR *dir; - struct dirent *de; - struct stat info; - - ngx_uint_t valid_info:1; /* unsigned valid_info:1; */ -} ngx_dir_t; - - -#endif /* _NGX_TYPES_H_INCLUDED_ */