diff options
author | Igor Sysoev <igor@sysoev.ru> | 2007-01-09 17:09:00 +0000 |
---|---|---|
committer | Jonathan Kolb <jon@b0g.us> | 2007-01-09 17:09:00 +0000 |
commit | 426223037017c6000f42bc041342171d1f666c6c (patch) | |
tree | 17cf24a9fec18aad176646cde33ea9ecdf44fd9d /src/http | |
parent | 0b70df4619adb2e1133feadc1063999583aee4b7 (diff) | |
download | nginx-426223037017c6000f42bc041342171d1f666c6c.tar.gz |
Changes with nginx 0.5.6 09 Jan 2007v0.5.6
*) Change: now the ngx_http_index_module ignores all methods except the
GET, HEAD, and POST methods.
*) Feature: the ngx_http_limit_zone_module.
*) Feature: the $binary_remote_addr variable.
*) Feature: the "ssl_session_cache" directives of the
ngx_http_ssl_module and ngx_imap_ssl_module.
*) Feature: the DELETE method supports recursive removal.
*) Bugfix: the byte-ranges were transferred incorrectly if the
$r->sendfile() was used.
Diffstat (limited to 'src/http')
-rw-r--r-- | src/http/modules/ngx_http_dav_module.c | 63 | ||||
-rw-r--r-- | src/http/modules/ngx_http_index_module.c | 4 | ||||
-rw-r--r-- | src/http/modules/ngx_http_limit_zone_module.c | 444 | ||||
-rw-r--r-- | src/http/modules/ngx_http_proxy_module.c | 2 | ||||
-rw-r--r-- | src/http/modules/ngx_http_range_filter_module.c | 270 | ||||
-rw-r--r-- | src/http/modules/ngx_http_realip_module.c | 12 | ||||
-rw-r--r-- | src/http/modules/ngx_http_ssl_module.c | 176 | ||||
-rw-r--r-- | src/http/modules/ngx_http_ssl_module.h | 26 | ||||
-rw-r--r-- | src/http/modules/perl/nginx.pm | 2 | ||||
-rw-r--r-- | src/http/ngx_http_request.c | 6 | ||||
-rw-r--r-- | src/http/ngx_http_request.h | 14 | ||||
-rw-r--r-- | src/http/ngx_http_upstream_round_robin.h | 2 | ||||
-rw-r--r-- | src/http/ngx_http_variables.c | 25 |
13 files changed, 887 insertions, 159 deletions
diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c index 0ecf8afa8..0d3c912b9 100644 --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -19,6 +19,11 @@ typedef struct { static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_dav_no_init(ngx_tree_ctx_t *ctx, + ngx_tree_ctx_t *prev); +static ngx_int_t ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path); +static ngx_int_t ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path); +static ngx_int_t ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); static void ngx_http_dav_put_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_dav_error(ngx_http_request_t *, ngx_err_t err, ngx_int_t not_found, char *failed, u_char *path); @@ -105,6 +110,7 @@ ngx_http_dav_handler(ngx_http_request_t *r) size_t root; ngx_int_t rc; ngx_str_t path; + ngx_tree_ctx_t tree; ngx_file_info_t fi; ngx_table_elt_t *depth; ngx_http_dav_loc_conf_t *dlcf; @@ -176,8 +182,23 @@ ngx_http_dav_handler(ngx_http_request_t *r) return NGX_HTTP_BAD_REQUEST; } - if (ngx_delete_dir(path.data) != NGX_FILE_ERROR) { - return NGX_HTTP_NO_CONTENT; + path.len -= 2; + + tree.init_handler = ngx_http_dav_no_init; + tree.file_handler = ngx_http_dav_delete_file; + tree.pre_tree_handler = ngx_http_dav_noop; + tree.post_tree_handler = ngx_http_dav_delete_dir; + tree.spec_handler = ngx_http_dav_delete_file; + tree.data = NULL; + tree.size = 0; + tree.log = r->connection->log; + + if (ngx_walk_tree(&tree, &path) == NGX_OK) { + + if (ngx_delete_dir(path.data) != NGX_FILE_ERROR) { + return NGX_HTTP_NO_CONTENT; + } + } failed = ngx_delete_dir_n; @@ -248,6 +269,44 @@ ngx_http_dav_handler(ngx_http_request_t *r) } +static ngx_int_t +ngx_http_dav_no_init(ngx_tree_ctx_t *ctx, ngx_tree_ctx_t *prev) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path) +{ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "http delete dir: \"%s\"", path->data); + + ngx_delete_dir(path->data); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) +{ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "http delete file: \"%s\"", path->data); + + ngx_delete_file(path->data); + + return NGX_OK; +} + + static void ngx_http_dav_put_handler(ngx_http_request_t *r) { diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c index 4df57f9ce..0f49551cc 100644 --- a/src/http/modules/ngx_http_index_module.c +++ b/src/http/modules/ngx_http_index_module.c @@ -140,6 +140,10 @@ ngx_http_index_handler(ngx_http_request_t *r) return NGX_DECLINED; } + if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { + return NGX_DECLINED; + } + /* TODO: Win32 */ if (r->zero_in_uri) { return NGX_DECLINED; diff --git a/src/http/modules/ngx_http_limit_zone_module.c b/src/http/modules/ngx_http_limit_zone_module.c new file mode 100644 index 000000000..396cb7fd3 --- /dev/null +++ b/src/http/modules/ngx_http_limit_zone_module.c @@ -0,0 +1,444 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_http.h> + + +typedef struct { + u_char color; + u_char len; + u_short conn; + u_char data[1]; +} ngx_http_limit_zone_node_t; + + +typedef struct { + ngx_shm_zone_t *shm_zone; + ngx_rbtree_node_t *node; +} ngx_http_limit_zone_cleanup_t; + + +typedef struct { + ngx_rbtree_t *rbtree; + ngx_int_t index; + ngx_str_t var; +} ngx_http_limit_zone_ctx_t; + + +typedef struct { + ngx_shm_zone_t *shm_zone; + ngx_uint_t conn; +} ngx_http_limit_zone_conf_t; + + +static void ngx_http_limit_zone_cleanup(void *data); + +static void *ngx_http_limit_zone_create_conf(ngx_conf_t *cf); +static char *ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_http_limit_zone_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_limit_zone_commands[] = { + + { ngx_string("limit_zone"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3, + ngx_http_limit_zone, + 0, + 0, + NULL }, + + { ngx_string("limit_conn"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_http_limit_conn, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_limit_zone_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_limit_zone_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_limit_zone_create_conf, /* create location configration */ + ngx_http_limit_zone_merge_conf /* merge location configration */ +}; + + +ngx_module_t ngx_http_limit_zone_module = { + NGX_MODULE_V1, + &ngx_http_limit_zone_module_ctx, /* module context */ + ngx_http_limit_zone_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_limit_zone_handler(ngx_http_request_t *r) +{ + size_t len, n; + uint32_t hash; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node, *sentinel; + ngx_pool_cleanup_t *cln; + ngx_http_variable_value_t *vv; + ngx_http_limit_zone_ctx_t *ctx; + ngx_http_limit_zone_node_t *lz; + ngx_http_limit_zone_conf_t *lzcf; + ngx_http_limit_zone_cleanup_t *lzcln; + + if (r->main->limit_zone_set) { + return NGX_DECLINED; + } + + lzcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_zone_module); + + if (lzcf->shm_zone == NULL) { + return NGX_DECLINED; + } + + ctx = lzcf->shm_zone->data; + + vv = ngx_http_get_indexed_variable(r, ctx->index); + + if (vv == NULL || vv->not_found) { + return NGX_DECLINED; + } + + r->limit_zone_set = 1; + + len = vv->len; + + hash = ngx_crc32_short(vv->data, len); + + cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_zone_cleanup_t)); + if (cln == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + shpool = (ngx_slab_pool_t *) lzcf->shm_zone->shm.addr; + + ngx_shmtx_lock(&shpool->mutex); + + node = ctx->rbtree->root; + sentinel = ctx->rbtree->sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + if (hash == node->key ){ + lz = (ngx_http_limit_zone_node_t *) &node->color; + + if (len == (size_t) lz->len + && ngx_strncmp(lz->data, vv->data, len) == 0) + { + if ((ngx_uint_t) lz->conn < lzcf->conn) { + lz->conn++; + goto done; + } + + ngx_shmtx_unlock(&shpool->mutex); + + return NGX_HTTP_SERVICE_UNAVAILABLE; + } + } + } + + n = offsetof(ngx_rbtree_node_t, color) + + offsetof(ngx_http_limit_zone_node_t, data) + + len; + + node = ngx_slab_alloc_locked(shpool, n); + if (node == NULL) { + ngx_shmtx_unlock(&shpool->mutex); + return NGX_HTTP_SERVICE_UNAVAILABLE; + } + + lz = (ngx_http_limit_zone_node_t *) &node->color; + + node->key = hash; + lz->len = (u_char) len; + lz->conn = 1; + ngx_memcpy(lz->data, vv->data, len); + + ngx_rbtree_insert(ctx->rbtree, node); + +done: + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "limit zone: %08XD %d", node->key, lz->conn); + + ngx_shmtx_unlock(&shpool->mutex); + + cln->handler = ngx_http_limit_zone_cleanup; + lzcln = cln->data; + + lzcln->shm_zone = lzcf->shm_zone; + lzcln->node = node; + + return NGX_DECLINED; +} + + +static void +ngx_http_limit_zone_cleanup(void *data) +{ + ngx_http_limit_zone_cleanup_t *lzcln = data; + + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node; + ngx_http_limit_zone_ctx_t *ctx; + ngx_http_limit_zone_node_t *lz; + + ctx = lzcln->shm_zone->data; + shpool = (ngx_slab_pool_t *) lzcln->shm_zone->shm.addr; + node = lzcln->node; + lz = (ngx_http_limit_zone_node_t *) &node->color; + + ngx_shmtx_lock(&shpool->mutex); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lzcln->shm_zone->shm.log, 0, + "limit zone cleanup: %08XD %d", node->key, lz->conn); + + lz->conn--; + + if (lz->conn == 0) { + ngx_rbtree_delete(ctx->rbtree, node); + ngx_slab_free_locked(shpool, node); + } + + ngx_shmtx_unlock(&shpool->mutex); +} + + +static ngx_int_t +ngx_http_limit_zone_init_zone(ngx_shm_zone_t *shm_zone, void *data) +{ + ngx_http_limit_zone_ctx_t *octx = data; + + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *sentinel; + ngx_http_limit_zone_ctx_t *ctx; + + ctx = shm_zone->data; + + if (octx) { + if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) { + ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, + "limit_zone \"%V\" use the \"%V\" variable " + "while previously it used the \"%V\" variable", + &shm_zone->name, &ctx->var, &octx->var); + return NGX_ERROR; + } + + ctx->rbtree = octx->rbtree; + + return NGX_OK; + } + + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); + if (ctx->rbtree == NULL) { + return NGX_ERROR; + } + + sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); + if (sentinel == NULL) { + return NGX_ERROR; + } + + ngx_rbtree_sentinel_init(sentinel); + + ctx->rbtree->root = sentinel; + ctx->rbtree->sentinel = sentinel; + ctx->rbtree->insert = ngx_rbtree_insert_value; + + return NGX_OK; +} + + +static void * +ngx_http_limit_zone_create_conf(ngx_conf_t *cf) +{ + ngx_http_limit_zone_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * conf->shm_zone = NULL; + * conf->conn = 0; + */ + + return conf; +} + + +static char * +ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_limit_zone_conf_t *prev = parent; + ngx_http_limit_zone_conf_t *conf = child; + + if (conf->shm_zone == NULL) { + *conf = *prev; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ssize_t n; + ngx_str_t *value; + ngx_shm_zone_t *shm_zone; + ngx_http_limit_zone_ctx_t *ctx; + + value = cf->args->elts; + + if (value[2].data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + value[2].len--; + value[2].data++; + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + ctx->index = ngx_http_get_variable_index(cf, &value[2]); + if (ctx->index == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + ctx->var = value[2]; + + n = ngx_parse_size(&value[3]); + + if (n == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid size of limit_zone \"%V\"", &value[3]); + return NGX_CONF_ERROR; + } + + if (n < (ngx_int_t) (8 * ngx_pagesize)) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "limit_zone \"%V\" is too small", &value[1]); + return NGX_CONF_ERROR; + } + + + shm_zone = ngx_shared_memory_add(cf, &value[1], n, + &ngx_http_limit_zone_module); + if (shm_zone == NULL) { + return NGX_CONF_ERROR; + } + + if (shm_zone->data) { + ctx = shm_zone->data; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "limit_zone \"%V\" is already bound to variable \"%V\"", + &value[1], &ctx->var); + return NGX_CONF_ERROR; + } + + shm_zone->init = ngx_http_limit_zone_init_zone; + shm_zone->data = ctx; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_limit_zone_conf_t *lzcf = conf; + + ngx_int_t n; + ngx_str_t *value; + + value = cf->args->elts; + + lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_limit_zone_module); + if (lzcf->shm_zone == NULL) { + return NGX_CONF_ERROR; + } + + n = ngx_atoi(value[2].data, value[2].len); + if (n <= 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid number of connections \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + lzcf->conn = n; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_limit_zone_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_PREACCESS_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_limit_zone_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 9083ee82a..63ee8fd80 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -2130,7 +2130,7 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) plcf->upstream.ssl->log = cf->log; if (ngx_ssl_create(plcf->upstream.ssl, - NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1) + NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1, NULL) != NGX_OK) { return NGX_CONF_ERROR; diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index ab346f9ba..55af30096 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -45,7 +45,16 @@ typedef struct { - ngx_str_t boundary_header; + off_t start; + off_t end; + ngx_str_t content_range; +} ngx_http_range_t; + + +typedef struct { + off_t offset; + ngx_str_t boundary_header; + ngx_array_t ranges; } ngx_http_range_filter_ctx_t; @@ -159,8 +168,13 @@ ngx_http_range_header_filter(ngx_http_request_t *r) return ngx_http_next_header_filter(r); } - if (ngx_array_init(&r->headers_out.ranges, r->pool, 2, - sizeof(ngx_http_range_t)) == NGX_ERROR) + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_range_filter_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + if (ngx_array_init(&ctx->ranges, r->pool, 1, sizeof(ngx_http_range_t)) + == NGX_ERROR) { return NGX_ERROR; } @@ -201,7 +215,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r) while (*p == ' ') { p++; } if (*p == ',' || *p == '\0') { - range = ngx_array_push(&r->headers_out.ranges); + range = ngx_array_push(&ctx->ranges); if (range == NULL) { return NGX_ERROR; } @@ -247,7 +261,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r) break; } - range = ngx_array_push(&r->headers_out.ranges); + range = ngx_array_push(&ctx->ranges); if (range == NULL) { return NGX_ERROR; } @@ -275,7 +289,6 @@ ngx_http_range_header_filter(ngx_http_request_t *r) /* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */ r->headers_out.status = rc; - r->headers_out.ranges.nelts = 0; content_range = ngx_list_push(&r->headers_out.headers); if (content_range == NULL) { @@ -304,9 +317,11 @@ ngx_http_range_header_filter(ngx_http_request_t *r) return rc; } + ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); + r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; - if (r->headers_out.ranges.nelts == 1) { + if (ctx->ranges.nelts == 1) { content_range = ngx_list_push(&r->headers_out.headers); if (content_range == NULL) { @@ -335,20 +350,17 @@ ngx_http_range_header_filter(ngx_http_request_t *r) r->headers_out.content_length_n = range->end - range->start; + if (r->headers_out.content_length) { + r->headers_out.content_length->hash = 0; + r->headers_out.content_length = NULL; + } + return ngx_http_next_header_filter(r); } /* TODO: what if no content_type ?? */ - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_range_filter_ctx_t)); - if (ctx == NULL) { - return NGX_ERROR; - } - - ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); - - len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof(CRLF "Content-Type: ") - 1 + r->headers_out.content_type.len @@ -417,8 +429,8 @@ ngx_http_range_header_filter(ngx_http_request_t *r) len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof("--" CRLF) - 1; - range = r->headers_out.ranges.elts; - for (i = 0; i < r->headers_out.ranges.nelts; i++) { + range = ctx->ranges.elts; + for (i = 0; i < ctx->ranges.nelts; i++) { /* the size of the range: "SSSS-EEEE/TTTT" CRLF CRLF */ @@ -440,7 +452,11 @@ ngx_http_range_header_filter(ngx_http_request_t *r) } r->headers_out.content_length_n = len; - r->headers_out.content_length = NULL; + + if (r->headers_out.content_length) { + r->headers_out.content_length->hash = 0; + r->headers_out.content_length = NULL; + } return ngx_http_next_header_filter(r); } @@ -449,106 +465,105 @@ ngx_http_range_header_filter(ngx_http_request_t *r) static ngx_int_t ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { + off_t start, last; + ngx_buf_t *b, *buf; ngx_uint_t i; - ngx_buf_t *b; ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; ngx_http_range_t *range; ngx_http_range_filter_ctx_t *ctx; - if (r->headers_out.ranges.nelts == 0) { + if (in == NULL) { return ngx_http_next_body_filter(r, in); } - /* - * the optimized version for the static files only - * that are passed in the single file buf - */ + ctx = ngx_http_get_module_ctx(r, ngx_http_range_body_filter_module); - if (in && in->buf->in_file && in->buf->last_buf) { - range = r->headers_out.ranges.elts; + if (ctx == NULL) { + return ngx_http_next_body_filter(r, in); + } - if (r->headers_out.ranges.nelts == 1) { - in->buf->file_pos = range->start; - in->buf->file_last = range->end; + buf = in->buf; - return ngx_http_next_body_filter(r, in); - } + if (ngx_buf_special(in->buf)) { + return ngx_http_next_body_filter(r, in); + } - ctx = ngx_http_get_module_ctx(r, ngx_http_range_body_filter_module); - ll = &out; + if (ctx->offset) { + goto overlapped; + } - for (i = 0; i < r->headers_out.ranges.nelts; i++) { + range = ctx->ranges.elts; - /* - * The boundary header of the range: - * CRLF - * "--0123456789" CRLF - * "Content-Type: image/jpeg" CRLF - * "Content-Range: bytes " - */ + if (!buf->last_buf) { - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } + if (buf->in_file) { + start = buf->file_pos + ctx->offset; + last = buf->file_last + ctx->offset; - b->memory = 1; - b->pos = ctx->boundary_header.data; - b->last = ctx->boundary_header.data + ctx->boundary_header.len; + } else { + start = buf->pos - buf->start + ctx->offset; + last = buf->last - buf->start + ctx->offset; + } - hcl = ngx_alloc_chain_link(r->pool); - if (hcl == NULL) { - return NGX_ERROR; + for (i = 0; i < ctx->ranges.nelts; i++) { + if (start > range[i].start || last < range[i].end) { + goto overlapped; } + } + } - hcl->buf = b; + /* + * the optimized version for the responses + * that are passed in the single buffer + */ + ctx->offset = ngx_buf_size(buf); - /* "SSSS-EEEE/TTTT" CRLF CRLF */ + if (ctx->ranges.nelts == 1) { - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } + if (buf->in_file) { + buf->file_pos = range->start; + buf->file_last = range->end; + } - b->temporary = 1; - b->pos = range[i].content_range.data; - b->last = range[i].content_range.data + range[i].content_range.len; + if (ngx_buf_in_memory(buf)) { + buf->pos = buf->start + (size_t) range->start; + buf->last = buf->start + (size_t) range->end; + } - rcl = ngx_alloc_chain_link(r->pool); - if (rcl == NULL) { - return NGX_ERROR; - } + return ngx_http_next_body_filter(r, in); + } - rcl->buf = b; + ll = &out; + for (i = 0; i < ctx->ranges.nelts; i++) { - /* the range data */ + /* + * The boundary header of the range: + * CRLF + * "--0123456789" CRLF + * "Content-Type: image/jpeg" CRLF + * "Content-Range: bytes " + */ - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } - b->in_file = 1; - b->file_pos = range[i].start; - b->file_last = range[i].end; - b->file = in->buf->file; + b->memory = 1; + b->pos = ctx->boundary_header.data; + b->last = ctx->boundary_header.data + ctx->boundary_header.len; - dcl = ngx_alloc_chain_link(r->pool); - if (dcl == NULL) { - return NGX_ERROR; - } + hcl = ngx_alloc_chain_link(r->pool); + if (hcl == NULL) { + return NGX_ERROR; + } - dcl->buf = b; + hcl->buf = b; - *ll = hcl; - hcl->next = rcl; - rcl->next = dcl; - ll = &dcl->next; - } - /* the last boundary CRLF "--0123456789--" CRLF */ + /* "SSSS-EEEE/TTTT" CRLF CRLF */ b = ngx_calloc_buf(r->pool); if (b == NULL) { @@ -556,34 +571,91 @@ ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } b->temporary = 1; - b->last_buf = 1; + b->pos = range[i].content_range.data; + b->last = range[i].content_range.data + range[i].content_range.len; - b->pos = ngx_palloc(r->pool, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN - + sizeof("--" CRLF) - 1); - if (b->pos == NULL) { + rcl = ngx_alloc_chain_link(r->pool); + if (rcl == NULL) { return NGX_ERROR; } - b->last = ngx_cpymem(b->pos, ctx->boundary_header.data, 4 + 10); - *b->last++ = '-'; *b->last++ = '-'; - *b->last++ = CR; *b->last++ = LF; + rcl->buf = b; - hcl = ngx_alloc_chain_link(r->pool); - if (hcl == NULL) { + + /* the range data */ + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { return NGX_ERROR; } - hcl->buf = b; - hcl->next = NULL; + b->in_file = buf->in_file; + b->temporary = buf->temporary; + b->memory = buf->memory; + b->mmap = buf->mmap; + b->file = buf->file; + + if (buf->in_file) { + buf->file_pos = range[i].start; + buf->file_last = range[i].end; + } + + if (ngx_buf_in_memory(buf)) { + buf->pos = buf->start + (size_t) range[i].start; + buf->last = buf->start + (size_t) range[i].end; + } + + dcl = ngx_alloc_chain_link(r->pool); + if (dcl == NULL) { + return NGX_ERROR; + } + + dcl->buf = b; *ll = hcl; + hcl->next = rcl; + rcl->next = dcl; + ll = &dcl->next; + } + + /* the last boundary CRLF "--0123456789--" CRLF */ + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->temporary = 1; + b->last_buf = 1; - return ngx_http_next_body_filter(r, out); + b->pos = ngx_palloc(r->pool, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + + sizeof("--" CRLF) - 1); + if (b->pos == NULL) { + return NGX_ERROR; } - /* TODO: alert */ + b->last = ngx_cpymem(b->pos, ctx->boundary_header.data, 4 + 10); + *b->last++ = '-'; *b->last++ = '-'; + *b->last++ = CR; *b->last++ = LF; + + hcl = ngx_alloc_chain_link(r->pool); + if (hcl == NULL) { + return NGX_ERROR; + } + + hcl->buf = b; + hcl->next = NULL; + + *ll = hcl; + + return ngx_http_next_body_filter(r, out); + +overlapped: + + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "range in overlapped buffers"); - return ngx_http_next_body_filter(r, in); + return NGX_ERROR; } diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c index df5859880..91ba695fd 100644 --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -103,18 +103,18 @@ ngx_http_realip_handler(ngx_http_request_t *r) ngx_http_realip_loc_conf_t *rlcf; if (r->realip_set) { - return NGX_OK; + return NGX_DECLINED; } rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module); if (rlcf->from == NULL) { - return NGX_OK; + return NGX_DECLINED; } if (rlcf->xfwd == 0) { if (r->headers_in.x_real_ip == NULL) { - return NGX_OK; + return NGX_DECLINED; } len = r->headers_in.x_real_ip->value.len; @@ -122,7 +122,7 @@ ngx_http_realip_handler(ngx_http_request_t *r) } else { if (r->headers_in.x_forwarded_for == NULL) { - return NGX_OK; + return NGX_DECLINED; } len = r->headers_in.x_forwarded_for->value.len; @@ -158,11 +158,11 @@ ngx_http_realip_handler(ngx_http_request_t *r) r->realip_set = 1; - return NGX_OK; + return NGX_DECLINED; } } - return NGX_OK; + return NGX_DECLINED; } diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 30c2d11de..e77e767ec 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -28,6 +28,9 @@ static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf); static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); +static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + #if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) static char *ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, @@ -115,6 +118,13 @@ static ngx_command_t ngx_http_ssl_commands[] = { ngx_http_ssl_nosupported, 0, 0, ngx_http_ssl_openssl097 }, #endif + { ngx_string("ssl_session_cache"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12, + ngx_http_ssl_session_cache, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("ssl_session_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_sec_slot, @@ -178,7 +188,7 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { }; -static u_char ngx_http_session_id_ctx[] = "HTTP"; +static ngx_str_t ngx_http_ssl_sess_id_ctx = ngx_string("HTTP"); static ngx_int_t @@ -257,35 +267,36 @@ ngx_http_ssl_add_variables(ngx_conf_t *cf) static void * ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) { - ngx_http_ssl_srv_conf_t *scf; + ngx_http_ssl_srv_conf_t *sscf; - scf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t)); - if (scf == NULL) { + sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t)); + if (sscf == NULL) { return NGX_CONF_ERROR; } /* * set by ngx_pcalloc(): * - * scf->protocols = 0; - - * scf->certificate.len = 0; - * scf->certificate.data = NULL; - * scf->certificate_key.len = 0; - * scf->certificate_key.data = NULL; - * scf->client_certificate.len = 0; - * scf->client_certificate.data = NULL; - * scf->ciphers.len = 0; - * scf->ciphers.data = NULL; + * sscf->protocols = 0; + * sscf->certificate.len = 0; + * sscf->certificate.data = NULL; + * sscf->certificate_key.len = 0; + * sscf->certificate_key.data = NULL; + * sscf->client_certificate.len = 0; + * sscf->client_certificate.data = NULL; + * sscf->ciphers.len = 0; + * sscf->ciphers.data = NULL; + * sscf->shm_zone = NULL; */ - scf->enable = NGX_CONF_UNSET; - scf->session_timeout = NGX_CONF_UNSET; - scf->verify = NGX_CONF_UNSET; - scf->verify_depth = NGX_CONF_UNSET; - scf->prefer_server_ciphers = NGX_CONF_UNSET; + sscf->enable = NGX_CONF_UNSET; + sscf->verify = NGX_CONF_UNSET; + sscf->verify_depth = NGX_CONF_UNSET; + sscf->prefer_server_ciphers = NGX_CONF_UNSET; + sscf->builtin_session_cache = NGX_CONF_UNSET; + sscf->session_timeout = NGX_CONF_UNSET; - return scf; + return sscf; } @@ -330,7 +341,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) conf->ssl.log = cf->log; - if (ngx_ssl_create(&conf->ssl, conf->protocols) != NGX_OK) { + if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -343,7 +354,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) cln->data = &conf->ssl; if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate, - &conf->certificate_key) != NGX_OK) + &conf->certificate_key) + != NGX_OK) { return NGX_CONF_ERROR; } @@ -359,7 +371,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) if (conf->verify) { if (ngx_ssl_client_certificate(cf, &conf->ssl, - &conf->client_certificate, conf->verify_depth) + &conf->client_certificate, + conf->verify_depth) != NGX_OK) { return NGX_CONF_ERROR; @@ -379,14 +392,123 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } - SSL_CTX_set_session_cache_mode(conf->ssl.ctx, SSL_SESS_CACHE_SERVER); + ngx_conf_merge_value(conf->builtin_session_cache, + prev->builtin_session_cache, + NGX_SSL_DFLT_BUILTIN_SCACHE); + + if (conf->shm_zone == NULL) { + conf->shm_zone = prev->shm_zone; + } + + if (ngx_ssl_session_cache(&conf->ssl, &ngx_http_ssl_sess_id_ctx, + conf->builtin_session_cache, + conf->shm_zone, conf->session_timeout) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_ssl_srv_conf_t *sscf = conf; + + size_t len; + ngx_str_t *value, name, size; + ngx_int_t n; + ngx_uint_t i, j; + + value = cf->args->elts; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strcmp(value[i].data, "builtin") == 0) { + sscf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE; + continue; + } + + if (value[i].len > sizeof("builtin:") - 1 + && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1) + == 0) + { + n = ngx_atoi(value[i].data + sizeof("builtin:") - 1, + value[i].len - (sizeof("builtin:") - 1)); + + if (n == NGX_ERROR) { + goto invalid; + } + + sscf->builtin_session_cache = n; + + continue; + } + + if (value[i].len > sizeof("shared:") - 1 + && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1) + == 0) + { + len = 0; + + for (j = sizeof("shared:") - 1; j < value[i].len; j++) { + if (value[i].data[j] == ':') { + break; + } + + len++; + } + + if (len == 0) { + goto invalid; + } + + name.len = len; + name.data = value[i].data + sizeof("shared:") - 1; + + size.len = value[i].len - j - 1; + size.data = name.data + len + 1; + + n = ngx_parse_size(&size); + + if (n == NGX_ERROR) { + goto invalid; + } - SSL_CTX_set_session_id_context(conf->ssl.ctx, ngx_http_session_id_ctx, - sizeof(ngx_http_session_id_ctx) - 1); + if (n < (ngx_int_t) (8 * ngx_pagesize)) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "session cache \"%V\" is too small", + &value[i]); - SSL_CTX_set_timeout(conf->ssl.ctx, conf->session_timeout); + return NGX_CONF_ERROR; + } + + sscf->shm_zone = ngx_shared_memory_add(cf, &name, n, + &ngx_http_ssl_module); + if (sscf->shm_zone == NULL) { + return NGX_CONF_ERROR; + } + + continue; + } + + goto invalid; + } + + if (sscf->shm_zone && sscf->builtin_session_cache == NGX_CONF_UNSET) { + sscf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE; + } return NGX_CONF_OK; + +invalid: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid session cache \"%V\"", &value[i]); + + return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index 85803096e..1ef1ffe0f 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -14,24 +14,28 @@ typedef struct { - ngx_flag_t enable; + ngx_flag_t enable; - ngx_ssl_t ssl; + ngx_ssl_t ssl; - ngx_flag_t prefer_server_ciphers; + ngx_flag_t prefer_server_ciphers; - ngx_uint_t protocols; + ngx_uint_t protocols; - ngx_int_t verify; - ngx_int_t verify_depth; + ngx_int_t verify; + ngx_int_t verify_depth; - time_t session_timeout; + ssize_t builtin_session_cache; - ngx_str_t certificate; - ngx_str_t certificate_key; - ngx_str_t client_certificate; + time_t session_timeout; - ngx_str_t ciphers; + ngx_str_t certificate; + ngx_str_t certificate_key; + ngx_str_t client_certificate; + + ngx_str_t ciphers; + + ngx_shm_zone_t *shm_zone; } ngx_http_ssl_srv_conf_t; diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm index 80c817d81..48018053c 100644 --- 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.5.5'; +our $VERSION = '0.5.6'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index f6dcd6a56..74ca4b841 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -976,10 +976,10 @@ ngx_http_read_request_header(ngx_http_request_t *r) } if (n == 0 || n == NGX_ERROR) { - c->error = rev->error; - c->log->action = "sending response to client"; + c->error = 1; + c->log->action = "reading client request headers"; - ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return NGX_ERROR; } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 9df5bd2ff..5cdcb9498 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -215,13 +215,6 @@ typedef struct { typedef struct { - off_t start; - off_t end; - ngx_str_t content_range; -} ngx_http_range_t; - - -typedef struct { ngx_list_t headers; ngx_uint_t status; @@ -245,7 +238,6 @@ typedef struct { ngx_str_t content_type; ngx_str_t charset; - ngx_array_t ranges; ngx_array_t cache_control; off_t content_length_n; @@ -438,6 +430,12 @@ struct ngx_http_request_s { #endif + /* + * instead of using the request context data in ngx_http_limit_zone_module + * we use the single bit in the request structure + */ + unsigned limit_zone_set:1; + #if 0 unsigned cachable:1; #endif diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h index 0f7d84b10..5d952217b 100644 --- a/src/http/ngx_http_upstream_round_robin.h +++ b/src/http/ngx_http_upstream_round_robin.h @@ -53,7 +53,7 @@ typedef struct { typedef struct { ngx_http_upstream_rr_peers_t *peers; ngx_uint_t current; - uintptr_t *tried; + uintptr_t *tried; uintptr_t data; } ngx_http_upstream_rr_peer_data_t; diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index ab43638f6..ac4a4a2f8 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -28,6 +28,8 @@ static ngx_int_t ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, static ngx_int_t ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_binary_remote_addr(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_remote_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r, @@ -115,6 +117,9 @@ static ngx_http_variable_t ngx_http_core_variables[] = { { ngx_string("host"), NULL, ngx_http_variable_host, 0, 0, 0 }, + { ngx_string("binary_remote_addr"), NULL, + ngx_http_variable_binary_remote_addr, 0, 0, 0 }, + { ngx_string("remote_addr"), NULL, ngx_http_variable_remote_addr, 0, 0, 0 }, { ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 }, @@ -696,6 +701,26 @@ ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v, static ngx_int_t +ngx_http_variable_binary_remote_addr(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + struct sockaddr_in *sin; + + /* AF_INET only */ + + sin = (struct sockaddr_in *) r->connection->sockaddr; + + v->len = sizeof(in_addr_t); + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + v->data = (u_char *) &sin->sin_addr.s_addr; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_variable_remote_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { |