# HG changeset patch # User Igor Sysoev # Date 1144353600 -14400 # Node ID 4cd3e70c4d6027d0aa226031cc78aa3b2f939be0 # Parent 654cbdc0401d4a700df16082be8da76502c37194 nginx 0.3.37 *) Feature: the "limit_except" directive. *) Feature: the "if" directive supports the "!~", "!~*", "-f", and "!-f" operators. *) Feature: the ngx_http_perl_module supports the $r->request_body method. *) Bugfix: in the ngx_http_addition_filter_module. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,16 @@ + +Changes with nginx 0.3.37 07 Apr 2006 + + *) Feature: the "limit_except" directive. + + *) Feature: the "if" directive supports the "!~", "!~*", "-f", and + "!-f" operators. + + *) Feature: the ngx_http_perl_module supports the $r->request_body + method. + + *) Bugfix: in the ngx_http_addition_filter_module. + Changes with nginx 0.3.36 05 Apr 2006 diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,17 @@ +Изменения в nginx 0.3.37 07.04.2006 + + *) Добавление: директива limit_except. + + *) Добавление: директива if поддерживает операторы "!~", "!~*", "-f" и + "!-f". + + *) Добавление: модуль ngx_http_perl_module поддерживает метод + $r->request_body. + + *) Исправление: в модуле ngx_http_addition_filter_module. + + Изменения в nginx 0.3.36 05.04.2006 *) Добавление: модуль ngx_http_addition_filter_module. diff --git a/auto/cc/msvc b/auto/cc/msvc --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -116,6 +116,12 @@ ngx_binout="-Fe" ngx_objext="obj" ngx_binext=".exe" +# Borland make +#ngx_long_start='@&&| +# ' +#ngx_long_end='|' + +# MS nmake ngx_long_start='@<< ' ngx_long_end='<<' @@ -123,6 +129,6 @@ ngx_long_regex_cont=' \ ' ngx_long_cont=' ' - +# MSVC understand / in path #ngx_regex_dirsep='\\' #ngx_dirsep="\\" 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.3.36" +#define NGINX_VER "nginx/0.3.37" #define NGINX_VAR "NGINX" #define NGX_OLDPID_EXT ".oldbin" diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -164,10 +164,14 @@ ngx_hash_init(ngx_hash_init_t *hinit, ng return NGX_ERROR; } - start = nelts / (ngx_cacheline_size / (2 * sizeof(void *)) - 1); + bucket_size = hinit->bucket_size - sizeof(void *); + + start = nelts / (bucket_size / (2 * sizeof(void *)) - 1); start = start ? start : 1; - bucket_size = hinit->bucket_size - sizeof(void *); + if (hinit->max_size > 10000 && hinit->max_size / nelts < 100) { + start = hinit->max_size - 1000; + } for (size = start; size < hinit->max_size; size++) { diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -21,8 +21,8 @@ */ -static -ngx_inline size_t ngx_sprint_uchar(u_char *text, u_char c, size_t len) +static ngx_inline size_t +ngx_sprint_uchar(u_char *text, u_char c, size_t len) { size_t n; ngx_uint_t c1, c2; diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -35,14 +35,16 @@ static ngx_int_t ngx_http_access_init(ng static ngx_command_t ngx_http_access_commands[] = { { ngx_string("allow"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF + |NGX_CONF_TAKE1, ngx_http_access_rule, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL }, { ngx_string("deny"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF + |NGX_CONF_TAKE1, ngx_http_access_rule, NGX_HTTP_LOC_CONF_OFFSET, 0, diff --git a/src/http/modules/ngx_http_addition_filter_module.c b/src/http/modules/ngx_http_addition_filter_module.c --- a/src/http/modules/ngx_http_addition_filter_module.c +++ b/src/http/modules/ngx_http_addition_filter_module.c @@ -16,8 +16,7 @@ typedef struct { typedef struct { - unsigned before_body_sent:1; - unsigned after_body_sent:1; + ngx_uint_t before_body_sent; } ngx_http_addition_ctx_t; @@ -92,6 +91,12 @@ ngx_http_addition_header_filter(ngx_http return ngx_http_next_header_filter(r); } + conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module); + + if (conf->before_body.len == 0 && conf->after_body.len == 0) { + return ngx_http_next_header_filter(r); + } + if (ngx_strncasecmp(r->headers_out.content_type.data, "text/html", sizeof("text/html") - 1) != 0) @@ -99,12 +104,6 @@ ngx_http_addition_header_filter(ngx_http return ngx_http_next_header_filter(r); } - conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module); - - if (conf->before_body.len == 0 && conf->after_body.len == 0) { - return ngx_http_next_header_filter(r); - } - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_addition_ctx_t)); if (ctx == NULL) { return NGX_ERROR; @@ -155,17 +154,14 @@ ngx_http_addition_body_filter(ngx_http_r for (cl = in; cl; cl = cl->next) { if (cl->buf->last_buf) { cl->buf->last_buf = 0; + cl->buf->sync = 1; last = 1; } } rc = ngx_http_next_body_filter(r, in); - if (rc == NGX_ERROR - || !last - || ctx->after_body_sent - || conf->after_body.len == 0) - { + if (rc == NGX_ERROR || !last || conf->after_body.len == 0) { return rc; } @@ -173,7 +169,7 @@ ngx_http_addition_body_filter(ngx_http_r return NGX_ERROR; } - ctx->after_body_sent = 1; + ngx_http_set_ctx(r, NULL, ngx_http_addition_filter_module); return ngx_http_send_special(r, NGX_HTTP_LAST); } diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -41,14 +41,16 @@ static ngx_conf_post_handler_pt ngx_htt static ngx_command_t ngx_http_auth_basic_commands[] = { { ngx_string("auth_basic"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF + |NGX_CONF_TAKE1, ngx_conf_set_str_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_auth_basic_loc_conf_t, realm), &ngx_http_auth_basic_p }, { ngx_string("auth_basic_user_file"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF + |NGX_CONF_TAKE1, ngx_conf_set_str_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_auth_basic_loc_conf_t, user_file), @@ -58,7 +60,6 @@ static ngx_command_t ngx_http_auth_basi }; - ngx_http_module_t ngx_http_auth_basic_module_ctx = { NULL, /* preconfiguration */ NULL, /* postconfiguration */ diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c --- a/src/http/modules/ngx_http_referer_module.c +++ b/src/http/modules/ngx_http_referer_module.c @@ -217,7 +217,7 @@ ngx_http_referer_merge_conf(ngx_conf_t * } if ((conf->no_referer == 1 || conf->blocked_referer == 1) - && conf->keys->keys.nelts == 0 && conf->keys->dns_wildcards.nelts) + && conf->keys->keys.nelts == 0 && conf->keys->dns_wildcards.nelts == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "the \"none\" or \"blocked\" referers are specified " 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 @@ -578,7 +578,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_ elts = lcf->codes->elts; - /* the inside directives must compile to the same code array */ + /* the inner directives must be compiled to the same code array */ nlcf = ctx->loc_conf[ngx_http_rewrite_module.ctx_index]; nlcf->codes = lcf->codes; @@ -629,9 +629,12 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_ static char * ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf) { + u_char *p; + size_t len; ngx_str_t *value, err; ngx_uint_t cur, last, n; ngx_http_script_code_pt *code; + ngx_http_script_file_code_t *fop; ngx_http_script_regex_code_t *regex; u_char errstr[NGX_MAX_CONF_ERRSTR]; @@ -667,11 +670,14 @@ ngx_http_rewrite_if_condition(ngx_conf_t value[last].data[value[last].len] = '\0'; } - if (value[cur].len > 1 && value[cur].data[0] == '$') { + len = value[cur].len; + p = value[cur].data; + + if (len > 1 && p[0] == '$') { if (cur != last && cur + 2 != last) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid condition \"%V\"", &value[cur]); + "invalid condition \"%V\"", &value[cur]); return NGX_CONF_ERROR; } @@ -685,7 +691,10 @@ ngx_http_rewrite_if_condition(ngx_conf_t cur++; - if (value[cur].len == 1 && value[cur].data[0] == '=') { + len = value[cur].len; + p = value[cur].data; + + if (len == 1 && p[0] == '=') { if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) { return NGX_CONF_ERROR; @@ -702,9 +711,8 @@ ngx_http_rewrite_if_condition(ngx_conf_t return NGX_CONF_OK; } - if (value[cur].len == 2 - && value[cur].data[0] == '!' && value[cur].data[1] == '=') - { + if (len == 2 && p[0] == '!' && p[1] == '=') { + if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) { return NGX_CONF_ERROR; } @@ -719,9 +727,10 @@ ngx_http_rewrite_if_condition(ngx_conf_t return NGX_CONF_OK; } - if ((value[cur].len == 1 && value[cur].data[0] == '~') - || (value[cur].len == 2 - && value[cur].data[0] == '~' && value[cur].data[1] == '*')) + if ((len == 1 && p[0] == '~') + || (len == 2 && p[0] == '~' && p[1] == '*') + || (len == 2 && p[0] == '!' && p[1] == '~') + || (len == 3 && p[0] == '!' && p[1] == '~' && p[2] == '*')) { regex = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(ngx_http_script_regex_code_t)); @@ -735,8 +744,8 @@ ngx_http_rewrite_if_condition(ngx_conf_t err.data = errstr; regex->regex = ngx_regex_compile(&value[last], - (value[cur].len == 2) ? NGX_REGEX_CASELESS : 0, - cf->pool, &err); + (p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0, + cf->pool, &err); if (regex->regex == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); @@ -746,6 +755,9 @@ ngx_http_rewrite_if_condition(ngx_conf_t regex->code = ngx_http_script_regex_start_code; regex->next = sizeof(ngx_http_script_regex_code_t); regex->test = 1; + if (p[0] == '!') { + regex->negative_test = 1; + } regex->name = value[last]; n = ngx_regex_capture_count(regex->regex); @@ -764,6 +776,46 @@ ngx_http_rewrite_if_condition(ngx_conf_t ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"%V\" in condition", &value[cur]); return NGX_CONF_ERROR; + + } else if ((len == 2 && p[0] == '-') + || (len == 3 && p[0] == '!' && p[1] == '-')) + { + if (cur + 1 != last) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid condition \"%V\"", &value[cur]); + return NGX_CONF_ERROR; + } + + value[last].data[value[last].len] = '\0'; + value[last].len++; + + if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) { + return NGX_CONF_ERROR; + } + + fop = ngx_http_script_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_script_file_code_t)); + if (fop == NULL) { + return NGX_CONF_ERROR; + } + + fop->code = ngx_http_script_file_code; + + if (p[1] == 'f') { + fop->op = ngx_http_script_file_plain; + return NGX_CONF_OK; + } + + if (p[0] == '!') { + if (p[2] == 'f') { + fop->op = ngx_http_script_file_not_plain; + return NGX_CONF_OK; + } + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid condition \"%V\"", &value[cur]); + return NGX_CONF_ERROR; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -261,6 +261,41 @@ header_in(r, key) RETVAL +SV * +request_body(r) + nginx r + + PREINIT: + + STRLEN len; + ngx_chain_t *cl; + + CODE: + + len = 0; + + for (cl = r->request_body->bufs; cl; cl = cl->next) { + if (cl->buf->in_file) { + XSRETURN_UNDEF; + } + + len += cl->buf->last - cl->buf->pos; + } + + if (len == 0) { + XSRETURN_UNDEF; + } + + RETVAL = newSV(len); + + for (cl = r->request_body->bufs; cl; cl = cl->next) { + sv_catpvn(RETVAL, cl->buf->pos, cl->buf->last - cl->buf->pos); + } + + OUTPUT: + RETVAL + + int header_out(r, key, value) nginx r 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 @@ -595,8 +595,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma if (rc == NGX_BUSY) { ngx_log_error(NGX_LOG_WARN, cf->log, 0, - "conflicting server name \"%V\", ignored", - &name[s].name); + "conflicting server name \"%V\" on %s, ignored", + &name[s].name, in_addr[a].listen_conf->addr); } } @@ -617,8 +617,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma if (rc == NGX_BUSY) { ngx_log_error(NGX_LOG_WARN, cf->log, 0, - "conflicting server name \"%V\", ignored", - &name[s].name); + "conflicting server name \"%V\" on %s, ignored", + &name[s].name, in_addr[a].listen_conf->addr); } } diff --git a/src/http/ngx_http_config.h b/src/http/ngx_http_config.h --- a/src/http/ngx_http_config.h +++ b/src/http/ngx_http_config.h @@ -42,7 +42,8 @@ typedef struct { #define NGX_HTTP_LOC_CONF 0x08000000 #define NGX_HTTP_UPS_CONF 0x10000000 #define NGX_HTTP_SIF_CONF 0x20000000 -#define NGX_HTTP_LIF_CONF 0x80000000 +#define NGX_HTTP_LIF_CONF 0x40000000 +#define NGX_HTTP_LMT_CONF 0x80000000 #define NGX_HTTP_MAIN_CONF_OFFSET offsetof(ngx_http_conf_ctx_t, main_conf) diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -11,6 +11,12 @@ #include +typedef struct { + char *name; + uint32_t method; +} ngx_http_method_name_t; + + #define NGX_HTTP_LOCATION_EXACT 1 #define NGX_HTTP_LOCATION_AUTO_REDIRECT 2 #define NGX_HTTP_LOCATION_NOREGEX 3 @@ -48,6 +54,8 @@ static char *ngx_http_core_listen(ngx_co static char *ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, @@ -225,6 +233,13 @@ static ngx_command_t ngx_http_core_comm 0, NULL }, + { ngx_string("limit_except"), + NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE, + ngx_http_core_limit_except, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { ngx_string("client_max_body_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -711,6 +726,11 @@ ngx_http_update_location_config(ngx_http clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + if (r->method & clcf->limit_except) { + r->loc_conf = clcf->limit_except_loc_conf; + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + } + r->connection->log->file = clcf->err_log->file; if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { r->connection->log->log_level = clcf->err_log->log_level; @@ -1949,6 +1969,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t * set by ngx_pcalloc(): * * lcf->root = { 0, NULL }; + * lcf->limit_except = 0; * lcf->post_action = { 0, NULL }; * lcf->types = NULL; * lcf->default_type = { 0, NULL }; @@ -2245,6 +2266,9 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx ls->addr = INADDR_ANY; } + n = ngx_inet_ntop(AF_INET, &ls->addr, ls->conf.addr, INET_ADDRSTRLEN + 6); + ngx_sprintf(&ls->conf.addr[n], ":%ui", ls->port); + if (cf->args->nelts == 2) { return NGX_CONF_OK; } @@ -2480,6 +2504,124 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c } +static ngx_http_method_name_t ngx_methods_names[] = { + { "GET", (uint32_t) ~NGX_HTTP_GET }, + { "HEAD", (uint32_t) ~NGX_HTTP_HEAD }, + { NULL, 0 } +}; + + +static char * +ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_core_loc_conf_t *clcf = conf; + + char *rv; + void *mconf; + ngx_str_t *value; + ngx_uint_t i; + ngx_conf_t save; + ngx_http_module_t *module; + ngx_http_conf_ctx_t *ctx, *pctx; + ngx_http_method_name_t *name; + ngx_http_core_loc_conf_t *lcf, **clcfp; + + if (clcf->limit_except) { + return "duplicate"; + } + + clcf->limit_except = 0xffffffff; + + value = cf->args->elts; + + for (i = 1; i < cf->args->nelts; i++) { + for (name = ngx_methods_names; name->name; name++) { + + if (ngx_strcasecmp(value[i].data, name->name) == 0) { + clcf->limit_except &= name->method; + goto next; + } + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid method \"%V\"", &value[i]); + return NGX_CONF_ERROR; + + next: + continue; + } + + if (!(clcf->limit_except & NGX_HTTP_GET)) { + clcf->limit_except &= (uint32_t) ~NGX_HTTP_HEAD; + } + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + pctx = cf->ctx; + ctx->main_conf = pctx->main_conf; + ctx->srv_conf = pctx->srv_conf; + + ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); + if (ctx->loc_conf == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->type != NGX_HTTP_MODULE) { + continue; + } + + module = ngx_modules[i]->ctx; + + if (module->create_loc_conf) { + + mconf = module->create_loc_conf(cf); + if (mconf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf; + } + } + + + lcf = ctx->loc_conf[ngx_http_core_module.ctx_index]; + clcf->limit_except_loc_conf = ctx->loc_conf; + lcf->loc_conf = ctx->loc_conf; + lcf->name = clcf->name; + lcf->noname = 1; + + if (clcf->locations.elts == NULL) { + if (ngx_array_init(&clcf->locations, cf->pool, 4, sizeof(void *)) + == NGX_ERROR) + { + return NGX_CONF_ERROR; + } + } + + clcfp = ngx_array_push(&clcf->locations); + if (clcfp == NULL) { + return NGX_CONF_ERROR; + } + + *clcfp = lcf; + + + save = *cf; + cf->ctx = ctx; + cf->cmd_type = NGX_HTTP_LMT_CONF; + + rv = ngx_conf_parse(cf, NULL); + + *cf = save; + + return rv; +} + + static char * ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { 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 @@ -28,6 +28,8 @@ typedef struct { ngx_uint_t deferred_accept; #endif + u_char addr[INET_ADDRSTRLEN + 6]; + } ngx_http_listen_conf_t; @@ -196,6 +198,9 @@ struct ngx_http_core_loc_conf_s { /* pointer to the modules' loc_conf */ void **loc_conf ; + uint32_t limit_except; + void **limit_except_loc_conf ; + ngx_http_handler_pt handler; ngx_str_t root; /* root, alias */ diff --git a/src/http/ngx_http_parse.c.orig b/src/http/ngx_http_parse.c.orig deleted file mode 100644 --- a/src/http/ngx_http_parse.c.orig +++ /dev/null @@ -1,1166 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - - -ngx_int_t -ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) -{ - u_char c, ch, *p, *m; - enum { - sw_start = 0, - sw_method, - sw_space_after_method, - sw_spaces_before_uri, - sw_schema, - sw_schema_slash, - sw_schema_slash_slash, - sw_host, - sw_port, - sw_after_slash_in_uri, - sw_check_uri, - sw_uri, - sw_http_09, - sw_http_H, - sw_http_HT, - sw_http_HTT, - sw_http_HTTP, - sw_first_major_digit, - sw_major_digit, - sw_first_minor_digit, - sw_minor_digit, - sw_almost_done - } state; - - state = r->state; - - for (p = b->pos; p < b->last; p++) { - ch = *p; - - /* gcc 2.95.2 and msvc 6.0 compile this switch as an jump table */ - - switch (state) { - - /* HTTP methods: GET, HEAD, POST */ - case sw_start: - r->request_start = p; - - if (ch == CR || ch == LF) { - break; - } - - if (ch < 'A' || ch > 'Z') { - return NGX_HTTP_PARSE_INVALID_METHOD; - } - - state = sw_method; - break; - - case sw_method: - if (ch == ' ') { - r->method_end = p - 1; - m = r->request_start; - - if (p - m == 3) { - - if (m[0] == 'G' && m[1] == 'E' && m[2] == 'T') { - r->method = NGX_HTTP_GET; - } - - } else if (p - m == 4) { - - if (m[0] == 'P' && m[1] == 'O' - && m[2] == 'S' && m[3] == 'T') - { - r->method = NGX_HTTP_POST; - - } else if (m[0] == 'H' && m[1] == 'E' - && m[2] == 'A' && m[3] == 'D') - { - r->method = NGX_HTTP_HEAD; - } - } - - state = sw_spaces_before_uri; - break; - } - - if (ch < 'A' || ch > 'Z') { - return NGX_HTTP_PARSE_INVALID_METHOD; - } - - break; - - /* single space after method */ - case sw_space_after_method: - switch (ch) { - case ' ': - state = sw_spaces_before_uri; - break; - default: - return NGX_HTTP_PARSE_INVALID_METHOD; - } - break; - - /* space* before URI */ - case sw_spaces_before_uri: - - c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'z') { - r->schema_start = p; - state = sw_schema; - break; - } - - switch (ch) { - case '/': - r->uri_start = p; - state = sw_after_slash_in_uri; - break; - case ' ': - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - case sw_schema: - - c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'z') { - break; - } - - switch (ch) { - case ':': - r->schema_end = p; - state = sw_schema_slash; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - case sw_schema_slash: - switch (ch) { - case '/': - state = sw_schema_slash_slash; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - case sw_schema_slash_slash: - switch (ch) { - case '/': - r->host_start = p; - state = sw_host; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - case sw_host: - - c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'z') { - break; - } - - if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') - { - break; - } - - switch (ch) { - case ':': - r->host_end = p; - state = sw_port; - break; - case '/': - r->host_end = p; - r->uri_start = p; - state = sw_after_slash_in_uri; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - case sw_port: - if (ch >= '0' && ch <= '9') { - break; - } - - switch (ch) { - case '/': - r->port_end = p; - r->uri_start = p; - state = sw_after_slash_in_uri; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - /* check "/.", "//", "%", and "\" (Win32) in URI */ - case sw_after_slash_in_uri: - - c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'z') { - state = sw_check_uri; - break; - } - - if (ch >= '0' && ch <= '9') { - state = sw_check_uri; - break; - } - - switch (ch) { - case ' ': - r->uri_end = p; - state = sw_http_09; - break; - case CR: - r->uri_end = p; - r->http_minor = 9; - state = sw_almost_done; - break; - case LF: - r->uri_end = p; - r->http_minor = 9; - goto done; - case '.': - r->complex_uri = 1; - state = sw_uri; - break; - case '%': - r->quoted_uri = 1; - state = sw_uri; - break; - case '/': - r->complex_uri = 1; - state = sw_uri; - break; -#if (NGX_WIN32) - case '\\': - r->complex_uri = 1; - state = sw_uri; - break; -#endif - case '?': - r->args_start = p + 1; - state = sw_uri; - break; - case '+': - r->plus_in_uri = 1; - break; - case '\0': - r->zero_in_uri = 1; - break; - default: - state = sw_check_uri; - break; - } - break; - - /* check "/", "%" and "\" (Win32) in URI */ - case sw_check_uri: - - c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'z') { - break; - } - - if (ch >= '0' && ch <= '9') { - break; - } - - switch (ch) { - case '/': - r->uri_ext = NULL; - state = sw_after_slash_in_uri; - break; - case '.': - r->uri_ext = p + 1; - break; - case ' ': - r->uri_end = p; - state = sw_http_09; - break; - case CR: - r->uri_end = p; - r->http_minor = 9; - state = sw_almost_done; - break; - case LF: - r->uri_end = p; - r->http_minor = 9; - goto done; -#if (NGX_WIN32) - case '\\': - r->complex_uri = 1; - state = sw_after_slash_in_uri; - break; -#endif - case '%': - r->quoted_uri = 1; - state = sw_uri; - break; - case '+': - r->plus_in_uri = 1; - break; - case '?': - r->args_start = p + 1; - state = sw_uri; - break; - case '\0': - r->zero_in_uri = 1; - break; - } - break; - - /* URI */ - case sw_uri: - switch (ch) { - case ' ': - r->uri_end = p; - state = sw_http_09; - break; - case CR: - r->uri_end = p; - r->http_minor = 9; - state = sw_almost_done; - break; - case LF: - r->uri_end = p; - r->http_minor = 9; - goto done; - case '+': - r->plus_in_uri = 1; - break; - case '\0': - r->zero_in_uri = 1; - break; - } - break; - - /* space+ after URI */ - case sw_http_09: - switch (ch) { - case ' ': - break; - case CR: - r->http_minor = 9; - state = sw_almost_done; - break; - case LF: - r->http_minor = 9; - goto done; - case 'H': - r->http_protocol.data = p; - state = sw_http_H; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - case sw_http_H: - switch (ch) { - case 'T': - state = sw_http_HT; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - case sw_http_HT: - switch (ch) { - case 'T': - state = sw_http_HTT; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - case sw_http_HTT: - switch (ch) { - case 'P': - state = sw_http_HTTP; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - case sw_http_HTTP: - switch (ch) { - case '/': - state = sw_first_major_digit; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - /* first digit of major HTTP version */ - case sw_first_major_digit: - if (ch < '1' || ch > '9') { - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - - r->http_major = ch - '0'; - state = sw_major_digit; - break; - - /* major HTTP version or dot */ - case sw_major_digit: - if (ch == '.') { - state = sw_first_minor_digit; - break; - } - - if (ch < '0' || ch > '9') { - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - - r->http_major = r->http_major * 10 + ch - '0'; - break; - - /* first digit of minor HTTP version */ - case sw_first_minor_digit: - if (ch < '0' || ch > '9') { - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - - r->http_minor = ch - '0'; - state = sw_minor_digit; - break; - - /* minor HTTP version or end of request line */ - case sw_minor_digit: - if (ch == CR) { - state = sw_almost_done; - break; - } - - if (ch == LF) { - goto done; - } - - if (ch < '0' || ch > '9') { - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - - r->http_minor = r->http_minor * 10 + ch - '0'; - break; - - /* end of request line */ - case sw_almost_done: - r->request_end = p - 1; - switch (ch) { - case LF: - goto done; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - } - } - - b->pos = p; - r->state = state; - - return NGX_AGAIN; - -done: - - b->pos = p + 1; - - if (r->request_end == NULL) { - r->request_end = p; - } - - r->http_version = r->http_major * 1000 + r->http_minor; - r->state = sw_start; - - if (r->http_version == 9 && r->method != NGX_HTTP_GET) { - return NGX_HTTP_PARSE_INVALID_09_METHOD; - } - - return NGX_OK; -} - - -ngx_int_t -ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) -{ - u_char c, ch, *p; - ngx_uint_t hash; - enum { - sw_start = 0, - sw_name, - sw_space_before_value, - sw_value, - sw_space_after_value, - sw_ignore_line, - sw_almost_done, - sw_header_almost_done - } state; - - state = r->state; - hash = r->header_hash; - - for (p = b->pos; p < b->last; p++) { - ch = *p; - - switch (state) { - - /* first char */ - case sw_start: - r->invalid_header = 0; - - switch (ch) { - case CR: - r->header_end = p; - state = sw_header_almost_done; - break; - case LF: - r->header_end = p; - goto header_done; - default: - state = sw_name; - r->header_name_start = p; - - c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'z') { - hash = c; - break; - } - - if (ch >= '0' && ch <= '9') { - hash = ch; - break; - } - - r->invalid_header = 1; - - break; - - } - break; - - /* header name */ - case sw_name: - c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'z') { - hash += c; - break; - } - - if (ch == ':') { - r->header_name_end = p; - state = sw_space_before_value; - break; - } - - if (ch == '-') { - hash += ch; - break; - } - - if (ch >= '0' && ch <= '9') { - hash += ch; - break; - } - - if (ch == CR) { - r->header_name_end = p; - r->header_start = p; - r->header_end = p; - state = sw_almost_done; - break; - } - - if (ch == LF) { - r->header_name_end = p; - r->header_start = p; - r->header_end = p; - goto done; - } - - /* IIS may send the duplicate "HTTP/1.1 ..." lines */ - if (ch == '/' - && r->upstream - && p - r->header_name_start == 4 - && ngx_strncmp(r->header_name_start, "HTTP", 4) == 0) - { - state = sw_ignore_line; - break; - } - - r->invalid_header = 1; - - break; - - /* space* before header value */ - case sw_space_before_value: - switch (ch) { - case ' ': - break; - case CR: - r->header_start = p; - r->header_end = p; - state = sw_almost_done; - break; - case LF: - r->header_start = p; - r->header_end = p; - goto done; - default: - r->header_start = p; - state = sw_value; - break; - } - break; - - /* header value */ - case sw_value: - switch (ch) { - case ' ': - r->header_end = p; - state = sw_space_after_value; - break; - case CR: - r->header_end = p; - state = sw_almost_done; - break; - case LF: - r->header_end = p; - goto done; - } - break; - - /* space* before end of header line */ - case sw_space_after_value: - switch (ch) { - case ' ': - break; - case CR: - state = sw_almost_done; - break; - case LF: - goto done; - default: - state = sw_value; - break; - } - break; - - /* ignore header line */ - case sw_ignore_line: - switch (ch) { - case LF: - state = sw_start; - break; - default: - break; - } - break; - - /* end of header line */ - case sw_almost_done: - switch (ch) { - case CR: - break; - case LF: - goto done; - default: - return NGX_HTTP_PARSE_INVALID_HEADER; - } - - /* end of header */ - case sw_header_almost_done: - switch (ch) { - case LF: - goto header_done; - default: - return NGX_HTTP_PARSE_INVALID_HEADER; - } - } - } - - b->pos = p; - r->state = state; - r->header_hash = hash; - - return NGX_AGAIN; - -done: - - b->pos = p + 1; - r->state = sw_start; - r->header_hash = hash; - - return NGX_OK; - -header_done: - - b->pos = p + 1; - r->state = sw_start; - - return NGX_HTTP_PARSE_HEADER_DONE; -} - - -ngx_int_t -ngx_http_parse_complex_uri(ngx_http_request_t *r) -{ - u_char c, ch, decoded, *p, *u; - enum { - sw_usual = 0, - sw_slash, - sw_dot, - sw_dot_dot, -#if (NGX_WIN32) - sw_dot_dot_dot, -#endif - sw_quoted, - sw_quoted_second - } state, quoted_state; - -#if (NGX_SUPPRESS_WARN) - decoded = '\0'; - quoted_state = sw_usual; -#endif - - state = sw_usual; - p = r->uri_start; - u = r->uri.data; - r->uri_ext = NULL; - r->args_start = NULL; - - ch = *p++; - - while (p <= r->uri_end) { - - /* - * we use "ch = *p++" inside the cycle, but this operation is safe, - * because after the URI there is always at least one charcter: - * the line feed - */ - - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "s:%d in:'%Xd:%c', out:'%c'", state, ch, ch, *u); - - switch (state) { - - case sw_usual: - switch(ch) { -#if (NGX_WIN32) - case '\\': - r->uri_ext = NULL; - - if (p == r->uri_start + r->uri.len) { - - /* - * we omit the last "\" to cause redirect because - * the browsers do not treat "\" as "/" in relative URL path - */ - - break; - } - - state = sw_slash; - *u++ = '/'; - break; -#endif - case '/': - r->uri_ext = NULL; - state = sw_slash; - *u++ = ch; - break; - case '%': - quoted_state = state; - state = sw_quoted; - break; - case '?': - r->args_start = p; - goto done; - case '.': - r->uri_ext = u + 1; - *u++ = ch; - break; - default: - *u++ = ch; - break; - } - ch = *p++; - break; - - case sw_slash: - switch(ch) { -#if (NGX_WIN32) - case '\\': -#endif - case '/': - break; - case '.': - state = sw_dot; - *u++ = ch; - break; - case '%': - quoted_state = state; - state = sw_quoted; - break; - case '?': - r->args_start = p; - goto done; - default: - state = sw_usual; - *u++ = ch; - break; - } - ch = *p++; - break; - - case sw_dot: - switch(ch) { -#if (NGX_WIN32) - case '\\': -#endif - case '/': - state = sw_slash; - u--; - break; - case '.': - state = sw_dot_dot; - *u++ = ch; - break; - case '%': - quoted_state = state; - state = sw_quoted; - break; - case '?': - r->args_start = p; - goto done; - default: - state = sw_usual; - *u++ = ch; - break; - } - ch = *p++; - break; - - case sw_dot_dot: - switch(ch) { -#if (NGX_WIN32) - case '\\': -#endif - case '/': - state = sw_slash; - u -= 4; - if (u < r->uri.data) { - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - while (*(u - 1) != '/') { - u--; - } - break; - case '%': - quoted_state = state; - state = sw_quoted; - break; - case '?': - r->args_start = p; - goto done; -#if (NGX_WIN32) - case '.': - state = sw_dot_dot_dot; - *u++ = ch; - break; -#endif - default: - state = sw_usual; - *u++ = ch; - break; - } - ch = *p++; - break; - -#if (NGX_WIN32) - case sw_dot_dot_dot: - switch(ch) { - case '\\': - case '/': - state = sw_slash; - u -= 5; - if (u < r->uri.data) { - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - while (*u != '/') { - u--; - } - if (u < r->uri.data) { - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - while (*(u - 1) != '/') { - u--; - } - break; - case '%': - quoted_state = state; - state = sw_quoted; - break; - case '?': - r->args_start = p; - goto done; - default: - state = sw_usual; - *u++ = ch; - break; - } - ch = *p++; - break; -#endif - - case sw_quoted: - if (ch >= '0' && ch <= '9') { - decoded = (u_char) (ch - '0'); - state = sw_quoted_second; - ch = *p++; - break; - } - - c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'f') { - decoded = (u_char) (c - 'a' + 10); - state = sw_quoted_second; - ch = *p++; - break; - } - - return NGX_HTTP_PARSE_INVALID_REQUEST; - - case sw_quoted_second: - if (ch >= '0' && ch <= '9') { - ch = (u_char) ((decoded << 4) + ch - '0'); - - if (ch == '%') { - state = sw_usual; - *u++ = ch; - ch = *p++; - break; - } - - if (ch == '\0') { - r->zero_in_uri = 1; - *u++ = ch; - ch = *p++; - } - - state = quoted_state; - break; - } - - c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'f') { - ch = (u_char) ((decoded << 4) + c - 'a' + 10); - if (ch == '?') { - *u++ = ch; - ch = *p++; - } - state = quoted_state; - break; - } - - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - } - -done: - - r->uri.len = u - r->uri.data; - r->uri.data[r->uri.len] = '\0'; - - if (r->uri_ext) { - r->exten.len = u - r->uri_ext; - r->exten.data = r->uri_ext; - } - - r->uri_ext = NULL; - - return NGX_OK; -} - - -ngx_int_t -ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri, - ngx_str_t *args, ngx_uint_t *flags) -{ - u_char ch, *p; - size_t len; - - len = uri->len; - p = uri->data; - - if (len == 0 || p[0] == '?') { - goto unsafe; - } - - if (p[0] == '.' && len == 3 && p[1] == '.' && (p[2] == '/' -#if (NGX_WIN32) - || p[2] == '\\' -#endif - )) - { - goto unsafe; - } - - for ( /* void */ ; len; len--) { - - ch = *p++; - - if (ch == '?') { - args->len = len - 1; - args->data = p; - uri->len -= len; - - return NGX_OK; - } - - if (ch == '\0') { - *flags |= NGX_HTTP_ZERO_IN_URI; - continue; - } - - if (ch != '/' -#if (NGX_WIN32) - && ch != '\\' -#endif - ) - { - continue; - } - - if (len > 2) { - - /* detect "/../" */ - - if (p[0] == '.' && p[1] == '.' && p[2] == '/') { - goto unsafe; - } - -#if (NGX_WIN32) - - if (p[2] == '\\') { - goto unsafe; - } - - if (len > 3) { - - /* detect "/.../" */ - - if (p[0] == '.' && p[1] == '.' && p[2] == '.' - && (p[3] == '/' || p[3] == '\\')) - { - goto unsafe; - } - } -#endif - } - } - - return NGX_OK; - -unsafe: - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "unsafe URI \"%V\" was detected", uri); - - return NGX_ERROR; -} - - -ngx_int_t -ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name, - ngx_str_t *value) -{ - ngx_uint_t i; - u_char *start, *last, *end, ch; - ngx_table_elt_t **h; - - h = headers->elts; - - for (i = 0; i < headers->nelts; i++) { - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0, - "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value); - - if (name->len > h[i]->value.len) { - continue; - } - - start = h[i]->value.data; - end = h[i]->value.data + h[i]->value.len; - - while (start < end) { - - if (ngx_strncasecmp(start, name->data, name->len) != 0) { - goto skip; - } - - for (start += name->len; start < end && *start == ' '; start++) { - /* void */ - } - - if (value == NULL) { - if (start == end || *start == ',') { - return i; - } - - goto skip; - } - - if (start == end || *start++ != '=') { - /* the invalid header value */ - goto skip; - } - - while (start < end && *start == ' ') { start++; } - - for (last = start; last < end && *last != ';'; last++) { - /* void */ - } - - value->len = last - start; - value->data = start; - - return i; - - skip: - - while (start < end) { - ch = *start++; - if (ch == ';' || ch == ',') { - break; - } - } - - while (start < end && *start == ' ') { start++; } - } - } - - return NGX_DECLINED; -} 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 @@ -410,6 +410,8 @@ void ngx_http_init_request(ngx_event_t * r->start_time = ngx_time(); + r->method = NGX_HTTP_UNKNOWN; + r->headers_in.content_length_n = -1; r->headers_in.keep_alive_n = -1; r->headers_out.content_length_n = -1; 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 @@ -19,9 +19,10 @@ #define NGX_HTTP_VERSION_10 1000 #define NGX_HTTP_VERSION_11 1001 -#define NGX_HTTP_GET 1 -#define NGX_HTTP_HEAD 2 -#define NGX_HTTP_POST 3 +#define NGX_HTTP_UNKNOWN 1 +#define NGX_HTTP_GET 2 +#define NGX_HTTP_HEAD 4 +#define NGX_HTTP_POST 8 #define NGX_HTTP_CONNECTION_CLOSE 1 #define NGX_HTTP_CONNECTION_KEEP_ALIVE 2 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 @@ -588,8 +588,15 @@ ngx_http_script_regex_start_code(ngx_htt e->ncaptures = 0; if (code->test) { - e->sp->len = 0; - e->sp->data = (u_char *) ""; + if (code->negative_test) { + e->sp->len = 1; + e->sp->data = (u_char *) "1"; + + } else { + e->sp->len = 0; + e->sp->data = (u_char *) ""; + } + e->sp++; e->ip += sizeof(ngx_http_script_regex_code_t); @@ -618,8 +625,15 @@ ngx_http_script_regex_start_code(ngx_htt e->ncaptures = code->ncaptures; if (code->test) { - e->sp->len = 1; - e->sp->data = (u_char *) "1"; + if (code->negative_test) { + e->sp->len = 0; + e->sp->data = (u_char *) ""; + + } else { + e->sp->len = 1; + e->sp->data = (u_char *) "1"; + } + e->sp++; e->ip += sizeof(ngx_http_script_regex_code_t); @@ -911,6 +925,69 @@ ngx_http_script_not_equal_code(ngx_http_ void +ngx_http_script_file_code(ngx_http_script_engine_t *e) +{ + ngx_err_t err; + ngx_file_info_t fi; + ngx_http_variable_value_t *value; + ngx_http_script_file_code_t *code; + + value = e->sp - 1; + + code = (ngx_http_script_file_code_t *) e->ip; + e->ip += sizeof(ngx_http_script_file_code_t); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script file op %p", code->op); + + if (ngx_file_info(value->data, &fi) == -1) { + err = ngx_errno; + + if (err != NGX_ENOENT && err != NGX_ENOTDIR) { + ngx_log_error(NGX_LOG_CRIT, e->request->connection->log, err, + ngx_file_info_n " \"%s\" failed", value->data); + } + + switch (code->op) { + case ngx_http_script_file_plain: + goto false; + case ngx_http_script_file_not_plain: + goto true; + } + + goto false; + } + + switch (code->op) { + case ngx_http_script_file_plain: + if (ngx_is_file(&fi)) { + goto true; + } + goto false; + + case ngx_http_script_file_not_plain: + if (ngx_is_file(&fi)) { + goto false; + } + goto true; + } + +false: + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script file op false"); + + *value = ngx_http_variable_null_value; + return; + +true: + + *value = ngx_http_variable_true_value; + return; +} + + +void ngx_http_script_complex_value_code(ngx_http_script_engine_t *e) { size_t 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 @@ -52,7 +52,6 @@ typedef struct { void *main; unsigned compile_args:1; - unsigned compile_null:1; unsigned complete_lengths:1; unsigned complete_values:1; @@ -94,6 +93,7 @@ typedef struct { uintptr_t next; uintptr_t test:1; + uintptr_t negative_test:1; uintptr_t uri:1; uintptr_t args:1; @@ -129,6 +129,18 @@ typedef struct { } ngx_http_script_return_code_t; +typedef enum { + ngx_http_script_file_plain = 0, + ngx_http_script_file_not_plain +} ngx_http_script_file_op_e; + + +typedef struct { + ngx_http_script_code_pt code; + uintptr_t op; +} ngx_http_script_file_code_t; + + typedef struct { ngx_http_script_code_pt code; uintptr_t next; @@ -177,6 +189,7 @@ void ngx_http_script_break_code(ngx_http void ngx_http_script_if_code(ngx_http_script_engine_t *e); void ngx_http_script_equal_code(ngx_http_script_engine_t *e); void ngx_http_script_not_equal_code(ngx_http_script_engine_t *e); +void ngx_http_script_file_code(ngx_http_script_engine_t *e); void ngx_http_script_complex_value_code(ngx_http_script_engine_t *e); void ngx_http_script_value_code(ngx_http_script_engine_t *e); void ngx_http_script_set_var_code(ngx_http_script_engine_t *e);