# HG changeset patch # User Igor Sysoev # Date 1112973535 0 # Node ID cd3117ad9aab9c58c6f7e677e551e1adbdeaba54 # Parent 005e65646622baacfe1dba75c4e6437c3d050f4a nginx-0.1.28-RELEASE import *) Bugfix: nginx hogs CPU while proxying the huge files. *) Bugfix: nginx could not be built by gcc 4.0 on Linux. diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -13,7 +13,7 @@ CORE_DEPS="src/core/nginx.h \ src/core/ngx_palloc.h \ src/core/ngx_array.h \ src/core/ngx_list.h \ - src/core/ngx_table.h \ + src/core/ngx_hash.h \ src/core/ngx_buf.h \ src/core/ngx_string.h \ src/core/ngx_parse.h \ @@ -34,6 +34,7 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_palloc.c \ src/core/ngx_array.c \ src/core/ngx_list.c \ + src/core/ngx_hash.c \ src/core/ngx_buf.c \ src/core/ngx_output_chain.c \ src/core/ngx_string.c \ @@ -243,6 +244,7 @@ HTTP_DEPS="src/http/ngx_http.h \ src/http/ngx_http_core_module.h \ src/http/ngx_http_cache.h \ src/http/ngx_http_variables.h \ + src/http/ngx_http_script.h \ src/http/ngx_http_upstream.h \ src/http/ngx_http_busy_lock.h \ src/http/ngx_http_log_module.h" @@ -258,6 +260,7 @@ HTTP_SRCS="src/http/ngx_http.c \ src/http/ngx_http_log_module.c \ src/http/ngx_http_request_body.c \ src/http/ngx_http_variables.c \ + src/http/ngx_http_script.c \ src/http/ngx_http_upstream.c \ src/http/ngx_http_parse_time.c \ src/http/modules/ngx_http_static_module.c \ @@ -320,6 +323,8 @@ HTTP_SSL_SRCS=src/http/modules/ngx_http_ HTTP_PROXY_MODULE=ngx_http_proxy_module +#HTTP_PROXY_SRCS=src/http/modules/ngx_http_proxy_module.c + HTTP_PROXY_INCS="src/http/modules/proxy" HTTP_PROXY_DEPS=src/http/modules/proxy/ngx_http_proxy_handler.h HTTP_PROXY_SRCS="src/http/modules/proxy/ngx_http_proxy_handler.c \ diff --git a/conf/mime.types b/conf/mime.types --- a/conf/mime.types +++ b/conf/mime.types @@ -4,21 +4,27 @@ types { text/xml xml rss; text/css css; text/plain txt; + text/x-component htc; image/gif gif; image/png png; image/jpeg jpeg jpg; image/x-icon ico; + image/x-jng jng; application/pdf pdf; application/x-shockwave-flash swf; application/x-javascript js; + application/x-rar-compressed rar; + application/x-xpinstall xpi; audio/mpeg mp3; audio/x-realaudio ra; video/mpeg mpeg mpg; video/quicktime mov; + video/x-flv flv; video/x-msvideo avi; video/x-ms-wmv wmv; + video/x-mng mng; } diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -9,14 +9,37 @@ nginx changelog + + + + +при проксировании больших файлов nginx сильно нагружал процессор. + + +nginx hogs CPU while proxing the huge files. + + + + + +nginx не собирался gcc 4.0 на Linux. + + +nginx could not be built by gcc 4.0 on Linux. + + + + + + -параметр blocked в директиве invalid_referers. +параметр blocked в директиве valid_referers. -the "blocked" parameter of the "invalid_referers" directive. +the "blocked" parameter of the "valid_referers" directive. 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.27" +#define NGINX_VER "nginx/0.1.28" #define NGINX_VAR "NGINX" #define NGX_NEWPID_EXT ".newbin" diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c --- a/src/core/ngx_buf.c +++ b/src/core/ngx_buf.c @@ -44,6 +44,27 @@ ngx_create_temp_buf(ngx_pool_t *pool, si ngx_chain_t * +ngx_alloc_chain_link(ngx_pool_t *pool) +{ + ngx_chain_t *cl; + + cl = pool->chain; + + if (cl) { + pool->chain = cl->next; + return cl; + } + + cl = ngx_palloc(pool, sizeof(ngx_chain_t)); + if (cl == NULL) { + return NULL; + } + + return cl; +} + + +ngx_chain_t * ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs) { u_char *p; 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 @@ -55,8 +55,6 @@ struct ngx_buf_s { }; -typedef struct ngx_chain_s ngx_chain_t; - struct ngx_chain_s { ngx_buf_t *buf; ngx_chain_t *next; @@ -119,7 +117,11 @@ ngx_chain_t *ngx_create_chain_of_bufs(ng #define ngx_alloc_buf(pool) ngx_palloc(pool, sizeof(ngx_buf_t)) #define ngx_calloc_buf(pool) ngx_pcalloc(pool, sizeof(ngx_buf_t)) -#define ngx_alloc_chain_link(pool) ngx_palloc(pool, sizeof(ngx_chain_t)) +ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool); +#define ngx_free_chain(pool, cl) \ + cl->next = pool->chain; \ + pool->chain = cl + ngx_int_t ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in); diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -137,7 +137,7 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t } ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "%s in %s:%d", + "%s in %s:%ui", rv, cf->conf_file->file.name.data, cf->conf_file->line); rc = NGX_ERROR; @@ -207,7 +207,7 @@ ngx_conf_handler(ngx_conf_t *cf, ngx_int if (!(cmd->type & cf->cmd_type)) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "directive \"%s\" in %s:%d " + "directive \"%s\" in %s:%ui " "is not allowed here", name->data, cf->conf_file->file.name.data, cf->conf_file->line); @@ -216,7 +216,7 @@ ngx_conf_handler(ngx_conf_t *cf, ngx_int if (!(cmd->type & NGX_CONF_BLOCK) && last != NGX_OK) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "directive \"%s\" in %s:%d " + "directive \"%s\" in %s:%ui " "is not terminated by \";\"", name->data, cf->conf_file->file.name.data, cf->conf_file->line); @@ -227,7 +227,7 @@ ngx_conf_handler(ngx_conf_t *cf, ngx_int && last != NGX_CONF_BLOCK_START) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "directive \"%s\" in %s:%d " + "directive \"%s\" in %s:%ui " "has not the opening \"{\"", name->data, cf->conf_file->file.name.data, cf->conf_file->line); @@ -276,7 +276,7 @@ ngx_conf_handler(ngx_conf_t *cf, ngx_int if (!valid) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "invalid number arguments in " - "directive \"%s\" in %s:%d", + "directive \"%s\" in %s:%ui", name->data, cf->conf_file->file.name.data, cf->conf_file->line); return NGX_ERROR; @@ -311,7 +311,7 @@ ngx_conf_handler(ngx_conf_t *cf, ngx_int } ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "the \"%s\" directive %s in %s:%d", + "the \"%s\" directive %s in %s:%ui", name->data, rv, cf->conf_file->file.name.data, cf->conf_file->line); @@ -323,7 +323,7 @@ ngx_conf_handler(ngx_conf_t *cf, ngx_int } ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "unknown directive \"%s\" in %s:%d", + "unknown directive \"%s\" in %s:%ui", name->data, cf->conf_file->file.name.data, cf->conf_file->line); @@ -360,7 +360,7 @@ ngx_conf_read_token(ngx_conf_t *cf) { if (cf->args->nelts > 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "unexpected end of file in %s:%d, " + "unexpected end of file in %s:%ui, " "expecting \";\" or \"}\"", cf->conf_file->file.name.data, cf->conf_file->line); @@ -423,7 +423,7 @@ ngx_conf_read_token(ngx_conf_t *cf) } ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "unexpected \"%c\" in %s:%d", + "unexpected \"%c\" in %s:%ui", ch, cf->conf_file->file.name.data, cf->conf_file->line); @@ -443,7 +443,7 @@ ngx_conf_read_token(ngx_conf_t *cf) case '{': if (cf->args->nelts == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "unexpected \"%c\" in %s:%d", + "unexpected \"%c\" in %s:%ui", ch, cf->conf_file->file.name.data, cf->conf_file->line); return NGX_ERROR; @@ -458,7 +458,7 @@ ngx_conf_read_token(ngx_conf_t *cf) case '}': if (cf->args->nelts > 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "unexpected \"}\" in %s:%d", + "unexpected \"}\" in %s:%ui", cf->conf_file->file.name.data, cf->conf_file->line); return NGX_ERROR; @@ -729,7 +729,7 @@ ngx_conf_log_error(ngx_uint_t level, ngx *buf = '\0'; } - ngx_log_error(level, cf->log, 0, "%s in %s:%d", + ngx_log_error(level, cf->log, 0, "%s in %s:%ui", errstr, cf->conf_file->file.name.data, cf->conf_file->line); } @@ -1065,7 +1065,7 @@ ngx_conf_check_num_bounds(ngx_conf_t *cf } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "value must be equal or more than %d", bounds->low); + "value must be equal or more than %i", bounds->low); return NGX_CONF_ERROR; } @@ -1075,7 +1075,7 @@ ngx_conf_check_num_bounds(ngx_conf_t *cf } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "value must be between %d and %d", + "value must be between %i and %i", bounds->low, bounds->high); return NGX_CONF_ERROR; diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -73,60 +73,60 @@ struct ngx_command_s { - ngx_str_t name; - int type; - char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); - int conf; - int offset; - void *post; + ngx_str_t name; + ngx_uint_t type; + char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + ngx_uint_t conf; + ngx_uint_t offset; + void *post; }; #define ngx_null_command { ngx_null_string, 0, NULL, 0, 0, NULL } struct ngx_open_file_s { - ngx_fd_t fd; - ngx_str_t name; + ngx_fd_t fd; + ngx_str_t name; #if 0 /* e.g. append mode, error_log */ - int flags; + ngx_uint_t flags; /* e.g. reopen db file */ - int (*handler)(void *data, ngx_open_file_t *file); - void *data; + ngx_uint_t (*handler)(void *data, ngx_open_file_t *file); + void *data; #endif }; struct ngx_module_s { - ngx_uint_t ctx_index; - ngx_uint_t index; - void *ctx; - ngx_command_t *commands; - ngx_uint_t type; - ngx_int_t (*init_module)(ngx_cycle_t *cycle); - ngx_int_t (*init_process)(ngx_cycle_t *cycle); + ngx_uint_t ctx_index; + ngx_uint_t index; + void *ctx; + ngx_command_t *commands; + ngx_uint_t type; + ngx_int_t (*init_module)(ngx_cycle_t *cycle); + ngx_int_t (*init_process)(ngx_cycle_t *cycle); #if 0 - ngx_int_t (*init_thread)(ngx_cycle_t *cycle); + ngx_int_t (*init_thread)(ngx_cycle_t *cycle); #endif }; typedef struct { - ngx_str_t name; - void *(*create_conf)(ngx_cycle_t *cycle); - char *(*init_conf)(ngx_cycle_t *cycle, void *conf); + ngx_str_t name; + void *(*create_conf)(ngx_cycle_t *cycle); + char *(*init_conf)(ngx_cycle_t *cycle, void *conf); } ngx_core_module_t; typedef struct { - ngx_file_t file; - ngx_buf_t *buffer; - ngx_uint_t line; + ngx_file_t file; + ngx_buf_t *buffer; + ngx_uint_t line; } ngx_conf_file_t; typedef char *(*ngx_conf_handler_pt)(ngx_conf_t *cf, - ngx_command_t *dummy, void *conf); + ngx_command_t *dummy, void *conf); struct ngx_conf_s { @@ -157,22 +157,22 @@ typedef struct { typedef struct { ngx_conf_post_handler_pt post_handler; - int low; - int high; + ngx_int_t low; + ngx_int_t high; } ngx_conf_num_bounds_t; typedef struct { - ngx_str_t name; - ngx_uint_t value; + ngx_str_t name; + ngx_uint_t value; } ngx_conf_enum_t; #define NGX_CONF_BITMASK_SET 1 typedef struct { - ngx_str_t name; - ngx_uint_t mask; + ngx_str_t name; + ngx_uint_t mask; } ngx_conf_bitmask_t; 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 @@ -12,6 +12,7 @@ typedef struct ngx_module_s ngx_mod typedef struct ngx_conf_s ngx_conf_t; typedef struct ngx_cycle_s ngx_cycle_t; typedef struct ngx_pool_s ngx_pool_t; +typedef struct ngx_chain_s ngx_chain_t; typedef struct ngx_log_s ngx_log_t; typedef struct ngx_array_s ngx_array_t; typedef struct ngx_open_file_s ngx_open_file_t; @@ -51,7 +52,7 @@ typedef void (*ngx_event_handler_pt)(ngx #include #include #include -#include +#include #include #include #include diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -54,7 +54,7 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t log = old_cycle->log; - pool = ngx_create_pool(16 * 1024, log); + pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); if (pool == NULL) { return NULL; } diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -12,6 +12,11 @@ #include +#ifndef NGX_CYCLE_POOL_SIZE +#define NGX_CYCLE_POOL_SIZE 16384 +#endif + + #define NGX_DEBUG_POINTS_STOP 1 #define NGX_DEBUG_POINTS_ABORT 2 diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c new file mode 100644 --- /dev/null +++ b/src/core/ngx_hash.c @@ -0,0 +1,160 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include + + +ngx_int_t +ngx_hash_init(ngx_hash_t *hash, ngx_pool_t *pool, void *names) +{ + u_char *p; + ngx_str_t *n, *bucket; + ngx_uint_t i, key, size, best, *test, buckets, min_buckets; + + test = ngx_alloc(hash->max_size * sizeof(ngx_uint_t), pool->log); + if (test == NULL) { + return NGX_ERROR; + } + + min_buckets = hash->bucket_limit + 1; + +#if (NGX_SUPPRESS_WARN) + best = 0; +#endif + + for (size = 1; size < hash->max_size; size++) { + + buckets = 0; + + for (i = 0; i < size; i++) { + test[i] = 0; + } + + for (n = (ngx_str_t *) names; + n->len; + n = (ngx_str_t *) ((char *) n + hash->bucket_size)) + { + key = 0; + + for (i = 0; i < n->len; i++) { + key += ngx_tolower(n->data[i]); + } + + key %= size; + + if (test[key] == hash->bucket_limit) { + break; + } + + test[key]++; + + if (buckets < test[key]) { + buckets = test[key]; + } + } + + if (n->len == 0) { + if (min_buckets > buckets) { + min_buckets = buckets; + best = size; + } + + if (hash->bucket_limit == 1) { + break; + } + } + } + + if (min_buckets == hash->bucket_limit + 1) { + ngx_log_error(NGX_LOG_EMERG, pool->log, 0, + "could not build the %s hash, you should increase " + "either %s_size: %i or %s_bucket_limit: %i", + hash->name, hash->name, hash->max_size, + hash->name, hash->bucket_limit); + ngx_free(test); + return NGX_ERROR; + } + + hash->buckets = ngx_pcalloc(pool, best * hash->bucket_size); + if (hash->buckets == NULL) { + ngx_free(test); + return NGX_ERROR; + } + + if (hash->bucket_limit != 1) { + + for (i = 0; i < best; i++) { + test[i] = 0; + } + + for (n = (ngx_str_t *) names; + n->len; + n = (ngx_str_t *) ((char *) n + hash->bucket_size)) + { + key = 0; + + for (i = 0; i < n->len; i++) { + key += ngx_tolower(n->data[i]); + } + + key %= best; + + test[key]++; + } + + for (i = 0; i < best; i++) { + if (test[i] == 0) { + continue; + } + + bucket = ngx_palloc(pool, test[i] * hash->bucket_size); + if (bucket == NULL) { + ngx_free(test); + return NGX_ERROR; + } + + hash->buckets[i] = bucket; + bucket->len = 0; + } + } + + for (n = (ngx_str_t *) names; + n->len; + n = (ngx_str_t *) ((char *) n + hash->bucket_size)) + { + key = 0; + + for (i = 0; i < n->len; i++) { + key += ngx_tolower(n->data[i]); + } + + key %= best; + + if (hash->bucket_limit == 1) { + p = (u_char *) hash->buckets + key * hash->bucket_size; + ngx_memcpy(p, n, hash->bucket_size); + continue; + } + + for (bucket = hash->buckets[key]; + bucket->len; + bucket = (ngx_str_t *) ((char *) bucket + hash->bucket_size)) + { + bucket->len &= 0x7fffffff; + } + + ngx_memcpy(bucket, n, hash->bucket_size); + bucket->len |= 0x80000000; + } + + ngx_free(test); + + hash->hash_size = best; + hash->min_buckets = min_buckets; + + return NGX_OK; +} diff --git a/src/core/ngx_hash.h b/src/core/ngx_hash.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_hash.h @@ -0,0 +1,37 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_HASH_H_INCLUDED_ +#define _NGX_HASH_H_INCLUDED_ + + +#include +#include + + +typedef struct { + void **buckets; + ngx_uint_t hash_size; + + ngx_uint_t max_size; + ngx_uint_t bucket_limit; + size_t bucket_size; + char *name; + ngx_uint_t min_buckets; +} ngx_hash_t; + + +typedef struct { + ngx_uint_t hash; + ngx_str_t key; + ngx_str_t value; +} ngx_table_elt_t; + + +ngx_int_t ngx_hash_init(ngx_hash_t *hash, ngx_pool_t *pool, void *names); + + +#endif /* _NGX_HASH_H_INCLUDED_ */ 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 @@ -119,8 +119,10 @@ ngx_output_chain(ngx_output_chain_ctx_t /* get the free buf */ if (ctx->free) { - ctx->buf = ctx->free->buf; - ctx->free = ctx->free->next; + 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) { diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c --- a/src/core/ngx_palloc.c +++ b/src/core/ngx_palloc.c @@ -22,6 +22,7 @@ ngx_create_pool(size_t size, ngx_log_t * p->end = (u_char *) p + size; p->next = NULL; p->large = NULL; + p->chain = NULL; p->log = log; return p; diff --git a/src/core/ngx_palloc.h b/src/core/ngx_palloc.h --- a/src/core/ngx_palloc.h +++ b/src/core/ngx_palloc.h @@ -33,6 +33,7 @@ struct ngx_pool_large_s { struct ngx_pool_s { u_char *last; u_char *end; + ngx_chain_t *chain; ngx_pool_t *next; ngx_pool_large_t *large; ngx_log_t *log; diff --git a/src/core/ngx_table.h b/src/core/ngx_table.h deleted file mode 100644 --- a/src/core/ngx_table.h +++ /dev/null @@ -1,27 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#ifndef _NGX_TABLE_H_INCLUDED_ -#define _NGX_TABLE_H_INCLUDED_ - - -#include -#include - - -typedef ngx_array_t ngx_table_t; - -typedef struct { - ngx_str_t key; - ngx_str_t value; -} ngx_table_elt_t; - - -#define ngx_create_table(p, n) ngx_create_array(p, n, 2 * sizeof(ngx_str_t)) -#define ngx_push_table(t) ngx_push_array(t) - - -#endif /* _NGX_TABLE_H_INCLUDED_ */ 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 @@ -84,7 +84,7 @@ static ngx_int_t ngx_event_pipe_read_ups ssize_t n, size; ngx_int_t rc; ngx_buf_t *b; - ngx_chain_t *chain, *cl; + ngx_chain_t *chain, *cl, *ln; if (p->upstream_eof || p->upstream_error || p->upstream_done) { return NGX_OK; @@ -293,7 +293,9 @@ static ngx_int_t ngx_event_pipe_read_ups } n -= size; + ln = cl; cl = cl->next; + ngx_free_chain(p->pool, ln); } else { cl->buf->last += n; @@ -686,8 +688,10 @@ ngx_int_t ngx_event_pipe_copy_input_filt } if (p->free) { - b = p->free->buf; - p->free = p->free->next; + cl = p->free; + b = cl->buf; + p->free = cl->next; + ngx_free_chain(p->pool, cl); } else { b = ngx_alloc_buf(p->pool); 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 @@ -396,7 +396,7 @@ ngx_http_fastcgi_handler(ngx_http_reques u->conf = &flcf->upstream; - u->location = flcf->location; + u->location0 = flcf->location; u->create_request = ngx_http_fastcgi_create_request; u->reinit_request = ngx_http_fastcgi_reinit_request; @@ -411,10 +411,10 @@ ngx_http_fastcgi_handler(ngx_http_reques u->log_ctx = r->connection->log->data; u->log_handler = ngx_http_upstream_log_error; - u->schema.len = sizeof("fastcgi://") - 1; - u->schema.data = (u_char *) "fastcgi://"; - u->uri.len = sizeof("/") - 1; - u->uri.data = (u_char *) "/"; + u->schema0.len = sizeof("fastcgi://") - 1; + u->schema0.data = (u_char *) "fastcgi://"; + u->uri0.len = sizeof("/") - 1; + u->uri0.data = (u_char *) "/"; r->upstream = u; @@ -1244,7 +1244,8 @@ ngx_http_fastcgi_reinit_request(ngx_http } -static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r) +static ngx_int_t +ngx_http_fastcgi_process_header(ngx_http_request_t *r) { u_char *start, *last; ngx_str_t *status_line, line; @@ -2127,16 +2128,16 @@ ngx_http_fastcgi_create_loc_conf(ngx_con conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; - conf->upstream.header_buffer_size = NGX_CONF_UNSET_SIZE; - conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.busy_buffers_size = NGX_CONF_UNSET_SIZE; - conf->upstream.max_temp_file_size = NGX_CONF_UNSET_SIZE; conf->upstream.temp_file_write_size = NGX_CONF_UNSET_SIZE; conf->upstream.redirect_errors = NGX_CONF_UNSET; + conf->upstream.pass_unparsed_uri = NGX_CONF_UNSET; conf->upstream.x_powered_by = NGX_CONF_UNSET; /* "fastcgi_cyclic_temp_file" is disabled */ @@ -2156,25 +2157,21 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf ngx_conf_merge_msec_value(conf->upstream.connect_timeout, prev->upstream.connect_timeout, 60000); + ngx_conf_merge_msec_value(conf->upstream.send_timeout, prev->upstream.send_timeout, 60000); - ngx_conf_merge_size_value(conf->upstream.send_lowat, - prev->upstream.send_lowat, 0); ngx_conf_merge_msec_value(conf->upstream.read_timeout, prev->upstream.read_timeout, 60000); - ngx_conf_merge_msec_value(conf->upstream.redirect_errors, - prev->upstream.redirect_errors, 0); - - ngx_conf_merge_msec_value(conf->upstream.x_powered_by, - prev->upstream.x_powered_by, 1); - + ngx_conf_merge_size_value(conf->upstream.send_lowat, + prev->upstream.send_lowat, 0); ngx_conf_merge_size_value(conf->upstream.header_buffer_size, prev->upstream.header_buffer_size, (size_t) ngx_pagesize); + ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, 8, ngx_pagesize); @@ -2267,6 +2264,23 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf ngx_garbage_collector_temp_handler, cf); + ngx_conf_merge_msec_value(conf->upstream.redirect_errors, + prev->upstream.redirect_errors, 0); + + ngx_conf_merge_msec_value(conf->upstream.pass_unparsed_uri, + prev->upstream.pass_unparsed_uri, 0); + + if (conf->upstream.pass_unparsed_uri && conf->location->len > 1) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "\"fastcgi_pass_unparsed_uri\" can be set for " + "location \"/\" or given by regular expression."); + return NGX_CONF_ERROR; + } + + ngx_conf_merge_msec_value(conf->upstream.x_powered_by, + prev->upstream.x_powered_by, 1); + + ngx_conf_merge_bitmask_value(conf->params, prev->params, (NGX_CONF_BITMASK_SET |NGX_HTTP_FASTCGI_REMOTE_ADDR @@ -2290,5 +2304,10 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf conf->vars = prev->vars; } + if (conf->peers == NULL) { + conf->peers = prev->peers; + conf->upstream = prev->upstream; + } + return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_proxy_module.c @@ -0,0 +1,1209 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include + + +typedef struct { + ngx_http_upstream_conf_t upstream; + + ngx_peers_t *peers; + + ngx_array_t *headers_set_len; + ngx_array_t *headers_set; + ngx_hash_t *headers_set_hash; + + 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; + ngx_flag_t pass_x_accel_expires; + + ngx_str_t *location0; + + ngx_str_t host_header; + ngx_str_t uri0; + + ngx_array_t *headers_sources; + ngx_array_t *headers_names; +} ngx_http_proxy_loc_conf_t; + + +typedef struct { + ngx_list_t headers; + + ngx_table_elt_t *date; + ngx_table_elt_t *server; + + ngx_table_elt_t *expires; + ngx_table_elt_t *cache_control; + ngx_table_elt_t *etag; + ngx_table_elt_t *x_accel_expires; + + ngx_table_elt_t *connection; + ngx_table_elt_t *content_type; + ngx_table_elt_t *content_length; + +#if (NGX_HTTP_GZIP) + ngx_table_elt_t *content_encoding; +#endif + + ngx_table_elt_t *last_modified; + ngx_table_elt_t *location; + ngx_table_elt_t *accept_ranges; + ngx_table_elt_t *x_pad; + + off_t content_length_n; +} ngx_http_proxy_headers_in_t; + + +static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r); +static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r); +static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r); +static ngx_int_t ngx_http_proxy_send_header(ngx_http_request_t *r); +static void ngx_http_proxy_abort_request(ngx_http_request_t *r); +static void ngx_http_proxy_finalize_request(ngx_http_request_t *r, + ngx_int_t rc); + +static ngx_int_t ngx_http_proxy_compile_header_start(ngx_table_elt_t *h, + ngx_array_t *lengths, ngx_array_t *values, ngx_uint_t value); +static ngx_int_t ngx_http_proxy_compile_header_end(ngx_array_t *lengths, + ngx_array_t *values); + +static ngx_int_t ngx_http_proxy_init(ngx_cycle_t *cycle); +static ngx_http_variable_value_t *ngx_http_proxy_host_variable + (ngx_http_request_t *r, uintptr_t data); +static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); + +static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +static char *ngx_http_proxy_set_x_var(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data); + +static ngx_conf_post_t ngx_http_proxy_lowat_post = + { ngx_http_proxy_lowat_check }; + +static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = { + { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, + { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, + { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, + { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, + { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_http_proxy_commands[] = { + + { ngx_string("proxy_pass"), + NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_proxy_pass, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("proxy_connect_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout), + NULL }, + + { ngx_string("proxy_send_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout), + NULL }, + + { ngx_string("proxy_send_lowat"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat), + &ngx_http_proxy_lowat_post }, + + { ngx_string("proxy_pass_unparsed_uri"), + 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, upstream.pass_unparsed_uri), + NULL }, + + { ngx_string("proxy_preserve_host"), + 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, 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, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, set_x_real_ip), + NULL }, + + { ngx_string("proxy_set_x_var"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_proxy_set_x_var, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("proxy_add_x_forwarded_for"), + 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, add_x_forwarded_for), + NULL }, + + { ngx_string("proxy_header_buffer_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.header_buffer_size), + NULL }, + + { ngx_string("proxy_read_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout), + NULL }, + + { ngx_string("proxy_buffers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_conf_set_bufs_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs), + NULL }, + + { ngx_string("proxy_busy_buffers_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size), + NULL }, + + { ngx_string("proxy_temp_path"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, + ngx_conf_set_path_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path), + (void *) ngx_garbage_collector_temp_handler }, + + { ngx_string("proxy_max_temp_file_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size), + NULL }, + + { ngx_string("proxy_temp_file_write_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size), + NULL }, + + { ngx_string("proxy_next_upstream"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream), + &ngx_http_proxy_next_upstream_masks }, + + { ngx_string("proxy_pass_server"), + 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, pass_server), + NULL }, + + { ngx_string("proxy_pass_x_accel_expires"), + 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, pass_x_accel_expires), + NULL }, + + ngx_null_command +}; + + +ngx_http_module_t ngx_http_proxy_module_ctx = { + NULL, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_proxy_create_loc_conf, /* create location configration */ + ngx_http_proxy_merge_loc_conf /* merge location configration */ +}; + + +ngx_module_t ngx_http_proxy_module = { + NGX_MODULE, + &ngx_http_proxy_module_ctx, /* module context */ + ngx_http_proxy_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_proxy_init, /* init module */ + NULL /* init process */ +}; + + +static ngx_str_t ngx_http_proxy_methods[] = { + ngx_string("GET"), + ngx_string("HEAD"), + ngx_string("POST") +}; + + +static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF; + +static ngx_str_t ngx_http_proxy_host = ngx_string("PROXY_HOST"); + + +#if (NGX_PCRE) +static ngx_str_t ngx_http_proxy_uri = ngx_string("/"); +#endif + + +#if 0 + +ngx_http_header_t ngx_http_proxy_headers_in[] = { + { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) }, + { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) }, + + { ngx_string("Expires"), offsetof(ngx_http_proxy_headers_in_t, expires) }, + { ngx_string("Cache-Control"), + offsetof(ngx_http_proxy_headers_in_t, cache_control) }, + { ngx_string("ETag"), offsetof(ngx_http_proxy_headers_in_t, etag) }, + { ngx_string("X-Accel-Expires"), + offsetof(ngx_http_proxy_headers_in_t, x_accel_expires) }, + + { ngx_string("Connection"), + offsetof(ngx_http_proxy_headers_in_t, connection) }, + { ngx_string("Content-Type"), + offsetof(ngx_http_proxy_headers_in_t, content_type) }, + { ngx_string("Content-Length"), + offsetof(ngx_http_proxy_headers_in_t, content_length) }, + +#if (NGX_HTTP_GZIP) + { ngx_string("Content-Encoding"), + offsetof(ngx_http_proxy_headers_in_t, content_encoding) }, +#endif + + { ngx_string("Last-Modified"), + offsetof(ngx_http_proxy_headers_in_t, last_modified) }, + { ngx_string("Location"), + offsetof(ngx_http_proxy_headers_in_t, location) }, + { ngx_string("Accept-Ranges"), + offsetof(ngx_http_proxy_headers_in_t, accept_ranges) }, + { ngx_string("X-Pad"), offsetof(ngx_http_proxy_headers_in_t, x_pad) }, + + { ngx_null_string, 0 } +}; + +#endif + + +static ngx_int_t +ngx_http_proxy_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_upstream_t *u; + ngx_http_proxy_loc_conf_t *plcf; + + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); + if (u == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + u->peer.log = r->connection->log; + u->peer.log_error = NGX_ERROR_ERR; + u->peer.peers = plcf->peers; + u->peer.tries = plcf->peers->number; +#if (NGX_THREADS) + u->peer.lock = &r->connection->lock; +#endif + + u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module; + + u->conf = &plcf->upstream; + + u->create_request = ngx_http_proxy_create_request; + u->reinit_request = ngx_http_proxy_reinit_request; + u->process_header = ngx_http_proxy_process_header; + u->send_header = ngx_http_proxy_send_header; + u->abort_request = ngx_http_proxy_abort_request; + u->finalize_request = ngx_http_proxy_finalize_request; + + u->pipe.input_filter = ngx_event_pipe_copy_input_filter; + + u->log_ctx = r->connection->log->data; + u->log_handler = ngx_http_upstream_log_error; + + u->schema0.len = sizeof("http://") - 1; + u->schema0.data = (u_char *) "http://"; + u->uri0 = plcf->uri0; + u->location0 = plcf->location0; + + r->upstream = u; + + rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_proxy_create_request(ngx_http_request_t *r) +{ + size_t len; + ngx_uint_t i, key; + uintptr_t escape; + ngx_buf_t *b; + ngx_str_t *hh; + ngx_chain_t *cl; + ngx_list_part_t *part; + ngx_table_elt_t *header; + ngx_http_upstream_t *u; + ngx_http_proxy_loc_conf_t *plcf; + ngx_http_script_code_pt code; + ngx_http_script_len_code_pt lcode; + ngx_http_script_lite_engine_t e; + + u = r->upstream; + + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + len = sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1; + + if (u->method) { + len += ngx_http_proxy_methods[u->method - 1].len + u->uri0.len; + } else { + len += r->method_name.len + u->uri0.len; + } + + escape = 0; + + if (plcf->upstream.pass_unparsed_uri && r->valid_unparsed_uri) { + len += r->unparsed_uri.len - 1; + + } else { + if (r->quoted_uri) { + escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->location0->len, + r->uri.len - u->location0->len, + NGX_ESCAPE_URI); + } + + len += r->uri.len - u->location0->len + escape + + sizeof("?") - 1 + r->args.len; + } + + + e.ip = plcf->headers_set_len->elts; + e.request = r; + + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_http_script_len_code_pt *) e.ip; + len += lcode(&e); + } + + + part = &r->headers_in.headers.part; + header = part->elts; + hh = (ngx_str_t *) plcf->headers_set_hash->buckets; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + key = header[i].hash % plcf->headers_set_hash->hash_size; + + if (hh[key].len == header[i].key.len + && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0) + { + continue; + } + + len += header[i].key.len + sizeof(": ") - 1 + + header[i].value.len + sizeof(CRLF) - 1; + } + + b = ngx_create_temp_buf(r->pool, len); + if (b == NULL) { + return NGX_ERROR; + } + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = b; + cl->next = NULL; + + r->request_body->bufs = cl; + + + /* the request line */ + + if (u->method) { + b->last = ngx_cpymem(b->last, + ngx_http_proxy_methods[u->method - 1].data, + ngx_http_proxy_methods[u->method - 1].len); + } else { + b->last = ngx_cpymem(b->last, r->method_name.data, r->method_name.len); + } + + b->last = ngx_cpymem(b->last, u->uri0.data, u->uri0.len); + + if (plcf->upstream.pass_unparsed_uri && r->valid_unparsed_uri) { + b->last = ngx_cpymem(b->last, r->unparsed_uri.data + 1, + r->unparsed_uri.len - 1); + } else { + if (escape) { + ngx_escape_uri(b->last, r->uri.data + u->location0->len, + r->uri.len - u->location0->len, NGX_ESCAPE_URI); + b->last += r->uri.len - u->location0->len + escape; + + } else { + b->last = ngx_cpymem(b->last, r->uri.data + u->location0->len, + r->uri.len - u->location0->len); + } + + if (r->args.len > 0) { + *b->last++ = '?'; + b->last = ngx_cpymem(b->last, r->args.data, r->args.len); + } + } + + b->last = ngx_cpymem(b->last, ngx_http_proxy_version, + sizeof(ngx_http_proxy_version) - 1); + + + e.ip = plcf->headers_set->elts; + e.pos = b->last; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + } + + b->last = e.pos; + + + part = &r->headers_in.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + key = header[i].hash % plcf->headers_set_hash->hash_size; + + if (hh[key].len == header[i].key.len + && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0) + { + continue; + } + + b->last = ngx_cpymem(b->last, header[i].key.data, header[i].key.len); + + *b->last++ = ':'; *b->last++ = ' '; + + b->last = ngx_cpymem(b->last, header[i].value.data, + header[i].value.len); + + *b->last++ = CR; *b->last++ = LF; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http proxy header: \"%V: %V\"", + &header[i].key, &header[i].value); + } + + /* add "\r\n" at the header end */ + *b->last++ = CR; *b->last++ = LF; + +#if (NGX_DEBUG) + { + ngx_str_t s; + + s.len = b->last - b->pos; + s.data = b->pos; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http proxy header:\n\"%V\"", &s); + } +#endif + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_proxy_reinit_request(ngx_http_request_t *r) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_http_proxy_process_header(ngx_http_request_t *r) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_http_proxy_send_header(ngx_http_request_t *r) +{ + return NGX_OK; +} + + +static void +ngx_http_proxy_abort_request(ngx_http_request_t *r) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "abort http proxy request"); + + return; +} + + +static void +ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "finalize http proxy request"); + + return; +} + + +static ngx_int_t +ngx_http_proxy_init(ngx_cycle_t *cycle) +{ +#if 0 + ngx_http_variable_t *var; + + var = ngx_http_add_variable(cf, &ngx_http_proxy_host, 1); + if (var == NULL) { + return NGX_ERROR; + } + + var->handler = ngx_http_proxy_host_variable; +#endif + + return NGX_OK; + +#if 0 + ngx_http_log_op_name_t *op; + + for (op = ngx_http_proxy_log_fmt_ops; op->name.len; op++) { /* void */ } + op->run = NULL; + + for (op = ngx_http_log_fmt_ops; op->run; op++) { + if (op->name.len == 0) { + op = (ngx_http_log_op_name_t *) op->run; + } + } + + op->run = (ngx_http_log_op_run_pt) ngx_http_proxy_log_fmt_ops; + +#endif +} + + +static ngx_http_variable_value_t * +ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data) +{ + ngx_http_variable_value_t *var; + ngx_http_proxy_loc_conf_t *plcf; + + var = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (var == NULL) { + return NULL; + } + + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + var->value = 0; + var->text = plcf->host_header; + + return var; +} + + +static void * +ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_proxy_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * conf->upstream.bufs.num = 0; + * conf->upstream.path = NULL; + * conf->upstream.next_upstream = 0; + * conf->upstream.temp_path = NULL; + */ + + conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; + + conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; + conf->upstream.header_buffer_size = NGX_CONF_UNSET_SIZE; + conf->upstream.busy_buffers_size = NGX_CONF_UNSET_SIZE; + conf->upstream.max_temp_file_size = NGX_CONF_UNSET_SIZE; + conf->upstream.temp_file_write_size = NGX_CONF_UNSET_SIZE; + + conf->upstream.redirect_errors = NGX_CONF_UNSET; + conf->upstream.pass_unparsed_uri = NGX_CONF_UNSET; + conf->upstream.x_powered_by = NGX_CONF_UNSET; + + /* "proxy_cyclic_temp_file" is disabled */ + conf->upstream.cyclic_temp_file = 0; + + 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; + + conf->pass_server = NGX_CONF_UNSET; + conf->pass_x_accel_expires = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_proxy_loc_conf_t *prev = parent; + ngx_http_proxy_loc_conf_t *conf = child; + + size_t size; + ngx_str_t *name; + ngx_table_elt_t *src; + ngx_http_variable_t *var; + + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, + prev->upstream.connect_timeout, 60000); + + ngx_conf_merge_msec_value(conf->upstream.send_timeout, + prev->upstream.send_timeout, 60000); + + ngx_conf_merge_msec_value(conf->upstream.read_timeout, + prev->upstream.read_timeout, 60000); + + ngx_conf_merge_size_value(conf->upstream.send_lowat, + prev->upstream.send_lowat, 0); + + ngx_conf_merge_size_value(conf->upstream.header_buffer_size, + prev->upstream.header_buffer_size, + (size_t) ngx_pagesize); + + ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, + 8, ngx_pagesize); + + if (conf->upstream.bufs.num < 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "there must be at least 2 \"proxy_buffers\""); + return NGX_CONF_ERROR; + } + + + size = conf->upstream.header_buffer_size; + if (size < conf->upstream.bufs.size) { + size = conf->upstream.bufs.size; + } + + + ngx_conf_merge_size_value(conf->upstream.busy_buffers_size, + prev->upstream.busy_buffers_size, + NGX_CONF_UNSET_SIZE); + + if (conf->upstream.busy_buffers_size == NGX_CONF_UNSET_SIZE) { + conf->upstream.busy_buffers_size = 2 * size; + + } else if (conf->upstream.busy_buffers_size < size) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_busy_buffers_size\" must be equal or bigger than " + "maximum of the value of \"proxy_header_buffer_size\" and " + "one of the \"proxy_buffers\""); + + return NGX_CONF_ERROR; + + } else if (conf->upstream.busy_buffers_size + > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_busy_buffers_size\" must be less than " + "the size of all \"proxy_buffers\" minus one buffer"); + + return NGX_CONF_ERROR; + } + + + ngx_conf_merge_size_value(conf->upstream.temp_file_write_size, + prev->upstream.temp_file_write_size, + NGX_CONF_UNSET_SIZE); + + if (conf->upstream.temp_file_write_size == NGX_CONF_UNSET_SIZE) { + conf->upstream.temp_file_write_size = 2 * size; + + } else if (conf->upstream.temp_file_write_size < size) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_temp_file_write_size\" must be equal or bigger than " + "maximum of the value of \"proxy_header_buffer_size\" and " + "one of the \"proxy_buffers\""); + + return NGX_CONF_ERROR; + } + + + ngx_conf_merge_size_value(conf->upstream.max_temp_file_size, + prev->upstream.max_temp_file_size, + NGX_CONF_UNSET_SIZE); + + if (conf->upstream.max_temp_file_size == NGX_CONF_UNSET_SIZE) { + + conf->upstream.max_temp_file_size = 1024 * 1024 * 1024; + + } else if (conf->upstream.max_temp_file_size != 0 + && conf->upstream.max_temp_file_size < size) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_max_temp_file_size\" must be equal to zero to disable " + "the temporary files usage or must be equal or bigger than " + "maximum of the value of \"fastcgi_header_buffer_size\" and " + "one of the \"fastcgi_buffers\""); + + return NGX_CONF_ERROR; + } + + ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, + prev->upstream.next_upstream, + (NGX_CONF_BITMASK_SET + |NGX_HTTP_UPSTREAM_FT_ERROR + |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); + + ngx_conf_merge_msec_value(conf->upstream.redirect_errors, + prev->upstream.redirect_errors, 0); + + ngx_conf_merge_msec_value(conf->upstream.pass_unparsed_uri, + prev->upstream.pass_unparsed_uri, 0); + + if (conf->upstream.pass_unparsed_uri && conf->location0->len > 1) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "\"proxy_pass_unparsed_uri\" can be set for " + "location \"/\" or given by regular expression."); + return NGX_CONF_ERROR; + } + + ngx_conf_merge_msec_value(conf->upstream.x_powered_by, + prev->upstream.x_powered_by, 1); + + 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); + + if (conf->peers == NULL) { + conf->peers = prev->peers; + conf->upstream = prev->upstream; + } + + if (conf->headers_set_hash == NULL) { + conf->headers_set_len = prev->headers_set_len; + conf->headers_set = prev->headers_set; + conf->headers_set_hash = prev->headers_set_hash; + } + + if (conf->headers_set_hash == NULL) { + + if (conf->headers_names == NULL) { + conf->headers_names = ngx_array_create(cf->pool, 4, + sizeof(ngx_str_t)); + if (conf->headers_names == NULL) { + return NGX_CONF_ERROR; + } + } + + if (conf->headers_sources == NULL) { + conf->headers_sources = ngx_array_create(cf->pool, 4, + sizeof(ngx_table_elt_t)); + if (conf->headers_sources == NULL) { + return NGX_CONF_ERROR; + } + } + + /* STUB */ + var = ngx_http_add_variable(cf, &ngx_http_proxy_host, 0); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + var->handler = ngx_http_proxy_host_variable; + /**/ + + + name = ngx_array_push(conf->headers_names); + if (name == NULL) { + return NGX_CONF_ERROR; + } + + name->len = sizeof("Host") - 1; + name->data = (u_char *) "Host"; + + src = ngx_array_push(conf->headers_sources); + if (src == NULL) { + return NGX_CONF_ERROR; + } + + src->hash = 0; + src->key.len = sizeof("Host") - 1; + src->key.data = (u_char *) "Host"; + src->value.len = sizeof("$PROXY_HOST") - 1; + src->value.data = (u_char *) "$PROXY_HOST"; + + + name = ngx_array_push(conf->headers_names); + if (name == NULL) { + return NGX_CONF_ERROR; + } + + name->len = sizeof("Connection") - 1; + name->data = (u_char *) "Connection"; + + src = ngx_array_push(conf->headers_sources); + if (src == NULL) { + return NGX_CONF_ERROR; + } + + src->hash = 0; + src->key.len = sizeof("Connection") - 1; + src->key.data = (u_char *) "Connection"; + src->value.len = sizeof("close") - 1; + src->value.data = (u_char *) "close"; + + + name = ngx_array_push(conf->headers_names); + if (name == NULL) { + return NGX_CONF_ERROR; + } + + name->len = 0; + name->data = NULL; + + + if (ngx_http_script_compile_lite(cf, conf->headers_sources, + &conf->headers_set_len, &conf->headers_set, + ngx_http_proxy_compile_header_start, + ngx_http_proxy_compile_header_end) != NGX_OK) + { + return NGX_CONF_ERROR; + } + + + conf->headers_set_hash = ngx_pcalloc(cf->pool, sizeof(ngx_hash_t)); + if (conf->headers_set_hash == NULL) { + return NGX_CONF_ERROR; + } + + conf->headers_set_hash->max_size = 100; + conf->headers_set_hash->bucket_limit = 1; + conf->headers_set_hash->bucket_size = sizeof(ngx_str_t); + conf->headers_set_hash->name = "proxy_headers"; + + if (ngx_hash_init(conf->headers_set_hash, cf->pool, + conf->headers_names->elts) != NGX_OK) + { + return NGX_CONF_ERROR; + } + +#if 0 + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, +#endif + ngx_log_error(NGX_LOG_NOTICE, cf->log, 0, + "proxy_headers hash size: %ui, " + "max buckets per entry: %ui", + conf->headers_set_hash->hash_size, + conf->headers_set_hash->min_buckets); + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_proxy_compile_header_start(ngx_table_elt_t *h, + ngx_array_t *lengths, ngx_array_t *values, ngx_uint_t value) +{ + u_char *p; + size_t size; + ngx_http_script_copy_code_t *copy; + + copy = ngx_array_push_n(lengths, sizeof(ngx_http_script_copy_code_t)); + if (copy == NULL) { + return NGX_ERROR; + } + + copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len; + copy->len = h->key.len + sizeof(": ") - 1; + + if (value) { + copy->len += h->value.len + sizeof(CRLF) - 1; + } + + size = (copy->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); + + copy = ngx_array_push_n(values, + sizeof(ngx_http_script_copy_code_t) + size); + if (copy == NULL) { + return NGX_ERROR; + } + + copy->code = ngx_http_script_copy; + copy->len = h->key.len + sizeof(": ") - 1; + + if (value) { + copy->len += h->value.len + sizeof(CRLF) - 1; + } + + p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); + + p = ngx_cpymem(p, h->key.data, h->key.len); + p = ngx_cpymem(p, ": ", sizeof(": ") - 1); + + if (value) { + p = ngx_cpymem(p, h->value.data, h->value.len); + ngx_memcpy(p, CRLF, sizeof(CRLF) - 1); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_proxy_compile_header_end(ngx_array_t *lengths, ngx_array_t *values) +{ + size_t size; + ngx_http_script_copy_code_t *copy; + + copy = ngx_array_push_n(lengths, sizeof(ngx_http_script_copy_code_t)); + if (copy == NULL) { + return NGX_ERROR; + } + + copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len; + copy->len = sizeof(CRLF) - 1; + + size = (sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + copy = ngx_array_push_n(values, + sizeof(ngx_http_script_copy_code_t) + size); + if (copy == NULL) { + return NGX_ERROR; + } + + copy->code = ngx_http_script_copy; + copy->len = sizeof(CRLF) - 1; + + ngx_memcpy((u_char *) copy + sizeof(ngx_http_script_copy_code_t), + CRLF, sizeof(CRLF) - 1); + + return NGX_OK; +} + + +static char * +ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_proxy_loc_conf_t *lcf = conf; + + ngx_uint_t i; + ngx_str_t *value, *url; + ngx_inet_upstream_t inet_upstream; + ngx_http_core_loc_conf_t *clcf; +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_unix_domain_upstream_t unix_upstream; +#endif + + value = cf->args->elts; + + url = &value[1]; + + if (ngx_strncasecmp(url->data, "http://", 7) != 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix"); + return NGX_CONF_ERROR; + } + + if (ngx_strncasecmp(url->data + 7, "unix:", 5) == 0) { + +#if (NGX_HAVE_UNIX_DOMAIN) + + ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); + + unix_upstream.name = *url; + unix_upstream.url.len = url->len - 7; + unix_upstream.url.data = url->data + 7; + unix_upstream.uri_part = 1; + + lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); + if (lcf->peers == NULL) { + return NGX_CONF_ERROR; + } + + lcf->peers->peer[0].uri_separator = ":"; + + lcf->host_header.len = sizeof("localhost") - 1; + lcf->host_header.data = (u_char *) "localhost"; + lcf->uri0 = unix_upstream.uri; +#if 0 + STUB + lcf->upstream->default_port = 1; +#endif + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the unix domain sockets are not supported " + "on this platform"); + return NGX_CONF_ERROR; + +#endif + + } else { + ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); + + inet_upstream.name = *url; + inet_upstream.url.len = url->len - 7; + inet_upstream.url.data = url->data + 7; + inet_upstream.default_port_value = 80; + inet_upstream.uri_part = 1; + + lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); + if (lcf->peers == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 0; i < lcf->peers->number; i++) { + lcf->peers->peer[i].uri_separator = ":"; + } + + lcf->host_header = inet_upstream.host_header; + lcf->uri0 = inet_upstream.uri; +#if 0 + STUB + lcf->port_text = inet_upstream.port_text; + lcf->upstream->default_port = inet_upstream.default_port; +#endif + } + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + clcf->handler = ngx_http_proxy_handler; + +#if (NGX_PCRE) + lcf->location0 = clcf->regex ? &ngx_http_proxy_uri : &clcf->name; +#else + lcf->location0 = &clcf->name; +#endif + + if (clcf->name.data[clcf->name.len - 1] == '/') { + clcf->auto_redirect = 1; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_proxy_set_x_var(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + return NGX_CONF_OK; +} + + +static char * +ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data) +{ +#if (NGX_FREEBSD) + ssize_t *np = data; + + if (*np >= ngx_freebsd_net_inet_tcp_sendspace) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_send_lowat\" must be less than %d " + "(sysctl net.inet.tcp.sendspace)", + ngx_freebsd_net_inet_tcp_sendspace); + + return NGX_CONF_ERROR; + } + +#elif !(NGX_HAVE_SO_SNDLOWAT) + ssize_t *np = data; + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "\"proxy_send_lowat\" is not supported, ignored"); + + *np = 0; + +#endif + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -1021,6 +1021,7 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com regex->uri = 1; regex->args = 1; regex->redirect = 0; + regex->break_cycle = 0; regex->name = value[1]; last = 0; @@ -1466,6 +1467,7 @@ ngx_http_rewrite_if_condition(ngx_conf_t regex->uri = 0; regex->args = 0; regex->redirect = 0; + regex->break_cycle = 0; regex->name = value[last]; return NGX_CONF_OK; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -197,6 +197,12 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * return NGX_CONF_ERROR; } +#if 0 + SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL); + SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_NO_SSLv3); + SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_SINGLE_DH_USE); +#endif + if (conf->ciphers.len) { if (SSL_CTX_set_cipher_list(conf->ssl_ctx, (const char *) conf->ciphers.data) == 0) 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 @@ -1332,6 +1332,11 @@ static char *ngx_http_proxy_merge_loc_co conf->x_vars = prev->x_vars; } + if (conf->peers == NULL) { + conf->peers = prev->peers; + conf->upstream = prev->upstream; + } + return NULL; } 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 @@ -90,7 +90,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma ngx_memzero(&in_ports, sizeof(ngx_array_t)); #endif - /* the main http context */ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); @@ -317,6 +316,22 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma cmcf->phases[NGX_HTTP_CONTENT_PHASE].type = NGX_OK; + cmcf->headers_in_hash.max_size = 100; + cmcf->headers_in_hash.bucket_limit = 1; + cmcf->headers_in_hash.bucket_size = sizeof(ngx_http_header_t); + cmcf->headers_in_hash.name = "http headers_in"; + + if (ngx_hash_init(&cmcf->headers_in_hash, cf->pool, ngx_http_headers_in) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, + "http headers_in hash size: %ui, max buckets per entry: %ui", + cmcf->headers_in_hash.hash_size, + cmcf->headers_in_hash.min_buckets); + /* * create the lists of ports, addresses and server names * to quickly find the server core module configuration at run-time diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -32,6 +32,7 @@ typedef struct ngx_http_variable_value_s #include #include #include +#include #if (NGX_HTTP_SSL) #include 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 @@ -48,6 +48,8 @@ typedef struct { ngx_http_phase_t phases[NGX_HTTP_LAST_PHASE]; ngx_array_t index_handlers; + ngx_hash_t headers_in_hash; + ngx_uint_t server_names_hash; ngx_uint_t server_names_hash_threshold; 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 @@ -11,7 +11,7 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) { - u_char ch, *p, *m; + u_char c, ch, *p, *m; enum { sw_start = 0, sw_method, @@ -109,7 +109,9 @@ ngx_int_t ngx_http_parse_request_line(ng /* space* before URI */ case sw_spaces_before_uri: - if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { + + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'f') { r->schema_start = p; state = sw_schema; break; @@ -128,7 +130,9 @@ ngx_int_t ngx_http_parse_request_line(ng break; case sw_schema: - if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { + + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'f') { break; } @@ -164,8 +168,13 @@ ngx_int_t ngx_http_parse_request_line(ng break; case sw_host: - if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') - || (ch >= '0' && ch <= '9') || ch == '.' || ch == '-') + + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'f') { + break; + } + + if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') { break; } @@ -204,10 +213,13 @@ ngx_int_t ngx_http_parse_request_line(ng /* check "/.", "//", "%", and "\" (Win32) in URI */ case sw_after_slash_in_uri: - if ((ch >= 'a' && ch <= 'z') - || (ch >= 'A' && ch <= 'Z') - || (ch >= '0' && ch <= '9')) - { + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'f') { + state = sw_check_uri; + break; + } + + if (ch >= '0' && ch <= '9') { state = sw_check_uri; break; } @@ -263,10 +275,12 @@ ngx_int_t ngx_http_parse_request_line(ng /* check "/", "%" and "\" (Win32) in URI */ case sw_check_uri: - if ((ch >= 'a' && ch <= 'z') - || (ch >= 'A' && ch <= 'Z') - || (ch >= '0' && ch <= '9')) - { + c = (u_char) (ch | 0x20); + if (c >= 'a' && c <= 'f') { + break; + } + + if (ch >= '0' && ch <= '9') { break; } @@ -490,7 +504,8 @@ done: ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) { - u_char c, ch, *p; + u_char c, ch, *p; + ngx_uint_t hash; enum { sw_start = 0, sw_name, @@ -504,6 +519,7 @@ ngx_int_t ngx_http_parse_header_line(ngx } state; state = r->state; + hash = r->header_hash; for (p = b->pos; p < b->last; p++) { ch = *p; @@ -528,14 +544,17 @@ ngx_int_t ngx_http_parse_header_line(ngx c = (u_char) (ch | 0x20); if (c >= 'a' && c <= 'z') { + hash = c; break; } if (ch == '-') { + hash = ch; break; } if (ch >= '0' && ch <= '9') { + hash = ch; break; } @@ -550,6 +569,7 @@ ngx_int_t ngx_http_parse_header_line(ngx case sw_name: c = (u_char) (ch | 0x20); if (c >= 'a' && c <= 'z') { + hash += c; break; } @@ -560,10 +580,12 @@ ngx_int_t ngx_http_parse_header_line(ngx } if (ch == '-') { + hash += ch; break; } if (ch >= '0' && ch <= '9') { + hash += ch; break; } @@ -681,6 +703,7 @@ ngx_int_t ngx_http_parse_header_line(ngx b->pos = p; r->state = state; + r->header_hash = hash; return NGX_AGAIN; @@ -688,6 +711,7 @@ done: b->pos = p + 1; r->state = sw_start; + r->header_hash = hash; return NGX_OK; 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 @@ -344,7 +344,7 @@ void ngx_http_init_request(ngx_event_t * if (c->ssl == NULL) { if (ngx_ssl_create_session(sscf->ssl_ctx, c, NGX_SSL_BUFFER) - == NGX_ERROR) + == NGX_ERROR) { ngx_http_close_connection(c); return; @@ -707,12 +707,15 @@ ngx_http_process_request_line(ngx_event_ static void ngx_http_process_request_headers(ngx_event_t *rev) { - ssize_t n; - ngx_int_t rc, rv, i; - ngx_str_t header; - ngx_table_elt_t *h, **cookie; - ngx_connection_t *c; - ngx_http_request_t *r; + ssize_t n; + ngx_int_t rc, rv; + ngx_uint_t key; + ngx_str_t header; + ngx_table_elt_t *h, **cookie; + ngx_connection_t *c; + ngx_http_header_t *hh; + ngx_http_request_t *r; + ngx_http_core_main_conf_t *cmcf; c = rev->data; r = c->data; @@ -728,6 +731,9 @@ ngx_http_process_request_headers(ngx_eve return; } + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + hh = (ngx_http_header_t *) cmcf->headers_in_hash.buckets; + rc = NGX_AGAIN; for ( ;; ) { @@ -791,6 +797,8 @@ ngx_http_process_request_headers(ngx_eve return; } + h->hash = r->header_hash; + h->key.len = r->header_name_end - r->header_name_start; h->key.data = r->header_name_start; h->key.data[h->key.len] = '\0'; @@ -812,19 +820,13 @@ ngx_http_process_request_headers(ngx_eve *cookie = h; } else { - - for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) { - if (ngx_http_headers_in[i].name.len != h->key.len) { - continue; - } - - if (ngx_strcasecmp(ngx_http_headers_in[i].name.data, - h->key.data) == 0) - { - *((ngx_table_elt_t **) ((char *) &r->headers_in - + ngx_http_headers_in[i].offset)) = h; - break; - } + key = h->hash % cmcf->headers_in_hash.hash_size; + + if (hh[key].name.len == h->key.len + && ngx_strcasecmp(hh[key].name.data, h->key.data) == 0) + { + *((ngx_table_elt_t **) + ((char *) &r->headers_in + hh[key].offset)) = h; } } @@ -1237,9 +1239,9 @@ ngx_http_find_virtual_server(ngx_http_re ngx_int_t rc; ngx_uint_t i, n, key, found; ngx_http_server_name_t *name; - ngx_http_core_main_conf_t *cmcf; + ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; - ngx_http_core_loc_conf_t *clcf; + ngx_http_core_main_conf_t *cmcf; if (r->virtual_names->hash) { cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); 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 @@ -386,11 +386,12 @@ struct ngx_http_request_s { u_char *header_name_end; u_char *header_start; u_char *header_end; + ngx_uint_t header_hash; }; -extern ngx_http_header_t ngx_http_headers_in[]; -extern ngx_http_header_t ngx_http_headers_out[]; +extern ngx_http_header_t ngx_http_headers_in[]; +extern ngx_http_header_t ngx_http_headers_out[]; diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -9,46 +9,186 @@ #include -u_char *ngx_http_script_copy(ngx_http_request_t *r, u_char *buf, void *data) +ngx_int_t +ngx_http_script_compile_lite(ngx_conf_t *cf, ngx_array_t *sources, + ngx_array_t **lengths, ngx_array_t **values, + ngx_http_script_compile_lite_start_pt start, + ngx_http_script_compile_lite_end_pt end) { - u_char **p = data; + uintptr_t *code; + ngx_uint_t i; + ngx_table_elt_t *src; + ngx_http_variable_t *var; + ngx_http_script_var_code_t *var_code; + + if (sources->nelts == 0) { + return NGX_OK; + } + + if (*lengths == NULL) { + *lengths = ngx_array_create(cf->pool, 64, 1); + if (*lengths == NULL) { + return NGX_ERROR; + } + } + + if (*values == NULL) { + *values = ngx_array_create(cf->pool, 256, 1); + if (*values == NULL) { + return NGX_ERROR; + } + } + + src = sources->elts; + for (i = 0; i < sources->nelts; i++) { + + if (src[i].value.data[0] == '$') { + if (start(&src[i], *lengths, *values, 0) != NGX_OK) { + return NGX_ERROR; + } + + src[i].value.len--; + src[i].value.data++; + + var = ngx_http_add_variable(cf, &src[i].value, 0); + + if (var == NULL) { + return NGX_ERROR; + } - ngx_http_script_code_t *code; + var_code = ngx_array_push_n(*lengths, + sizeof(ngx_http_script_var_code_t)); + if (var_code == NULL) { + return NGX_ERROR; + } + + var_code->code = (ngx_http_script_code_pt) + ngx_http_script_copy_var_len; + var_code->index = var->index; + + + var_code = ngx_array_push_n(*values, + sizeof(ngx_http_script_var_code_t)); + if (var_code == NULL) { + return NGX_ERROR; + } + + var_code->code = ngx_http_script_copy_var; + var_code->index = var->index; + - code = (ngx_http_script_code_t *) - ((char *) data - sizeof(ngx_http_script_code_t)); + if (end(*lengths, *values) != NGX_OK) { + return NGX_ERROR; + } + + continue; + } + + if (start(&src[i], *lengths, *values, 1) != NGX_OK) { + return NGX_ERROR; + } + } - return ngx_cpymem(buf, *p, code->data_len); + code = ngx_array_push_n(*lengths, sizeof(uintptr_t)); + if (code == NULL) { + return NGX_ERROR; + } + + *code = (uintptr_t) NULL; + + code = ngx_array_push_n(*values, sizeof(uintptr_t)); + if (code == NULL) { + return NGX_ERROR; + } + + *code = (uintptr_t) NULL; + + return NGX_OK; } -u_char *ngx_http_script_header_in(ngx_http_request_t *r, - u_char *buf, void *data) +#if 0 + +static void * +ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size) { - size_t *offset = data; + if (*codes == NULL) { + *codes = ngx_array_create(pool, 256, 1); + if (*codes == NULL) { + return NULL; + } + } - ngx_table_elt_t *h; + return ngx_array_push_n(*codes, size); +} + +#endif + - h = *(ngx_table_elt_t **) (((char *) r->headers_in) + *offset); +size_t +ngx_http_script_copy_len(ngx_http_script_engine_t *e) +{ + ngx_http_script_copy_code_t *code; - return ngx_cpymem(p, h->value.data, h->value.len); + code = (ngx_http_script_copy_code_t *) e->lite.ip; + + e->lite.ip += sizeof(ngx_http_script_copy_code_t); + + return code->len; } -u_char *ngx_http_script_request_line(ngx_http_request_t *r, - u_char *buf, void *data) +void +ngx_http_script_copy(ngx_http_script_engine_t *e) { - return ngx_cpymem(p, r->request_line.data, r->request_line.len); + ngx_http_script_copy_code_t *code; + + code = (ngx_http_script_copy_code_t *) e->lite.ip; + + e->lite.pos = ngx_cpymem(e->lite.pos, + e->lite.ip + sizeof(ngx_http_script_copy_code_t), + code->len); + + e->lite.ip += sizeof(ngx_http_script_copy_code_t) + + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1)); } -u_char *ngx_http_script_status(ngx_http_request_t *r, u_char *buf, void *data) +size_t +ngx_http_script_copy_var_len(ngx_http_script_engine_t *e) { - return ngx_sprintf(buf, "%ui", r->headers_out.status); + ngx_http_variable_value_t *value; + ngx_http_script_var_code_t *code; + + code = (ngx_http_script_var_code_t *) e->lite.ip; + + e->lite.ip += sizeof(ngx_http_script_var_code_t); + + value = ngx_http_get_indexed_variable(e->lite.request, code->index); + + if (value == NULL || value == NGX_HTTP_VARIABLE_NOT_FOUND) { + return 0; + } + + return value->text.len; } -u_char *ngx_http_script_sent(ngx_http_request_t *r, u_char *buf, void *data) +void +ngx_http_script_copy_var(ngx_http_script_engine_t *e) { - return ngx_sprintf(buf, "%O", r->connection->sent); + ngx_http_variable_value_t *value; + ngx_http_script_var_code_t *code; + + code = (ngx_http_script_var_code_t *) e->lite.ip; + + e->lite.ip += sizeof(ngx_http_script_var_code_t); + + value = ngx_http_get_indexed_variable(e->lite.request, code->index); + + if (value == NULL || value == NGX_HTTP_VARIABLE_NOT_FOUND) { + return; + } + + e->lite.pos = ngx_cpymem(e->lite.pos, value->text.data, value->text.len); } diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -13,14 +13,54 @@ #include -typedef u_char *(*ngx_http_script_code_pt) (ngx_http_request_t *r, - u_char *buf, void *data); +typedef struct { + u_char *ip; + u_char *pos; + ngx_http_request_t *request; +} ngx_http_script_lite_engine_t; + + +typedef struct { + ngx_http_script_lite_engine_t lite; +} ngx_http_script_engine_t; + + +typedef void (*ngx_http_script_code_pt) (ngx_http_script_engine_t *e); +typedef size_t (*ngx_http_script_len_code_pt) + (ngx_http_script_lite_engine_t *e); + +typedef ngx_int_t (*ngx_http_script_compile_lite_start_pt) (ngx_table_elt_t *h, + ngx_array_t *lengths, ngx_array_t *values, ngx_uint_t value); +typedef ngx_int_t (*ngx_http_script_compile_lite_end_pt) (ngx_array_t *lengths, + ngx_array_t *values); + -typedef struct ngx_http_script_code_s { - size_t data_len; - size_t code_len; - ngx_http_script_code_pt code; -} ngx_http_script_code_t; +typedef struct { + ngx_http_script_code_pt code; + uintptr_t len; +} ngx_http_script_copy_code_t; + + +typedef struct { + ngx_http_script_code_pt code; + uintptr_t index; +} ngx_http_script_var_code_t; + + +ngx_int_t ngx_http_script_compile_lite(ngx_conf_t *cf, ngx_array_t *sources, + ngx_array_t **lengths, ngx_array_t **values, + ngx_http_script_compile_lite_start_pt start, + ngx_http_script_compile_lite_end_pt end); + + +static void *ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, + size_t size); + +size_t ngx_http_script_copy_len(ngx_http_script_engine_t *e); +void ngx_http_script_copy(ngx_http_script_engine_t *e); +size_t ngx_http_script_copy_var_len(ngx_http_script_engine_t *e); +void ngx_http_script_copy_var(ngx_http_script_engine_t *e); + #endif /* _NGX_HTTP_SCRIPT_H_INCLUDED_ */ diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -1135,7 +1135,7 @@ u_char * ngx_http_upstream_log_error(ngx_log_t *log, u_char *buf, size_t len) { u_char *p; - ngx_int_t escape; + uintptr_t escape; ngx_http_log_ctx_t *ctx; ngx_http_request_t *r; ngx_http_upstream_t *u; @@ -1153,29 +1153,29 @@ ngx_http_upstream_log_error(ngx_log_t *l &r->connection->addr_text, &r->server_name, &r->unparsed_uri, - &u->schema, + &u->schema0, &peer->peers->peer[peer->cur_peer].name, peer->peers->peer[peer->cur_peer].uri_separator, - &u->uri); + &u->uri0); len -= p - buf; buf = p; if (r->quoted_uri) { - escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->location->len, - r->uri.len - u->location->len, + escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->location0->len, + r->uri.len - u->location0->len, NGX_ESCAPE_URI); } else { escape = 0; } if (escape) { - if (len >= r->uri.len - u->location->len + escape) { + if (len >= r->uri.len - u->location0->len + escape) { - ngx_escape_uri(buf, r->uri.data + u->location->len, - r->uri.len - u->location->len, NGX_ESCAPE_URI); + ngx_escape_uri(buf, r->uri.data + u->location0->len, + r->uri.len - u->location0->len, NGX_ESCAPE_URI); - buf += r->uri.len - u->location->len + escape; - len -= r->uri.len - u->location->len + escape; + buf += r->uri.len - u->location0->len + escape; + len -= r->uri.len - u->location0->len + escape; if (r->args.len) { p = ngx_snprintf(buf, len, "?%V", &r->args); @@ -1186,19 +1186,19 @@ ngx_http_upstream_log_error(ngx_log_t *l return ngx_http_log_error_info(r, buf, len); } - p = ngx_palloc(r->pool, r->uri.len - u->location->len + escape); + p = ngx_palloc(r->pool, r->uri.len - u->location0->len + escape); if (p == NULL) { return buf; } - ngx_escape_uri(p, r->uri.data + u->location->len, - r->uri.len - u->location->len, NGX_ESCAPE_URI); + ngx_escape_uri(p, r->uri.data + u->location0->len, + r->uri.len - u->location0->len, NGX_ESCAPE_URI); - p = ngx_cpymem(buf, p, r->uri.len - u->location->len + escape); + p = ngx_cpymem(buf, p, r->uri.len - u->location0->len + escape); } else { - p = ngx_cpymem(buf, r->uri.data + u->location->len, - r->uri.len - u->location->len); + p = ngx_cpymem(buf, r->uri.data + u->location0->len, + r->uri.len - u->location0->len); } len -= p - buf; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -55,6 +55,7 @@ typedef struct { ngx_bufs_t bufs; ngx_flag_t redirect_errors; + ngx_flag_t pass_unparsed_uri; ngx_flag_t x_powered_by; ngx_flag_t cyclic_temp_file; @@ -87,9 +88,9 @@ struct ngx_http_upstream_s { ngx_int_t rc); ngx_uint_t method; - ngx_str_t schema; - ngx_str_t uri; - ngx_str_t *location; + ngx_str_t schema0; + ngx_str_t uri0; + ngx_str_t *location0; ngx_http_log_ctx_t *log_ctx; ngx_log_handler_pt log_handler; 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 @@ -231,6 +231,12 @@ ngx_http_write_filter(ngx_http_request_t return NGX_ERROR; } + for (cl = ctx->out; cl && cl != chain; /* void */) { + ln = cl; + cl = cl->next; + ngx_free_chain(r->pool, ln); + } + ctx->out = chain; if (chain || (last && c->buffered)) { diff --git a/src/os/unix/ngx_setproctitle.c b/src/os/unix/ngx_setproctitle.c --- a/src/os/unix/ngx_setproctitle.c +++ b/src/os/unix/ngx_setproctitle.c @@ -88,7 +88,7 @@ ngx_setproctitle(char *title) ngx_os_argv[1] = NULL; - p = ngx_cpystrn((u_char *) ngx_os_argv[0], "nginx: ", + p = ngx_cpystrn((u_char *) ngx_os_argv[0], (u_char *) "nginx: ", ngx_os_argv_last - ngx_os_argv[0]); p = ngx_cpystrn(p, (u_char *) title, ngx_os_argv_last - (char *) p);