Mercurial > hg > nginx
view src/http/ngx_http_script.h @ 9217:6765e5f6d991
Upstream: fixed X-Accel-Redirect handling from cache files.
The X-Accel-Redirect header might appear in cache files if its handling
is ignored with the "proxy_ignore_headers" directive. If the cache file
is later served with different settings, ngx_http_upstream_process_headers()
used to call ngx_http_upstream_finalize_request(NGX_DECLINED), which
is not expected to happen before the cleanup handler is installed and
resulted in ngx_http_finalize_request(NGX_DONE) (after 5994:5abf5af257a7,
nginx 1.7.11), leading to unexpected request counter decrement, "request
count is zero" alerts, and segmentation faults.
Similarly, errors in ngx_http_upstream_process_headers() resulted in
ngx_http_upstream_finalize_request(NGX_HTTP_INTERNAL_SERVER_ERROR) being
called. This is also not expected to happen before the cleanup handler is
installed, and resulted in ngx_http_finalize_request(NGX_DONE) without
proper request finalization.
Fix is to avoid calling ngx_http_upstream_finalize_request() from
ngx_http_upstream_process_headers(), notably when the cleanup handler
is not yet installed. Errors are now simply return NGX_ERROR, so the
caller is responsible for proper finalization by calling either
ngx_http_finalize_request() or ngx_http_upstream_finalize_request().
And X-Accel-Redirect handling now does not call
ngx_http_upstream_finalize_request(NGX_DECLINED) if no cleanup handler
is installed.
Reported by Jiří Setnička
(https://mailman.nginx.org/pipermail/nginx-devel/2024-February/HWLYHOO3DDB3XTFT6X3GRMXIEJ3SJRUA.html).
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Tue, 20 Feb 2024 01:23:43 +0300 |
parents | 3ab8e1e2f0f7 |
children |
line wrap: on
line source
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #ifndef _NGX_HTTP_SCRIPT_H_INCLUDED_ #define _NGX_HTTP_SCRIPT_H_INCLUDED_ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_http.h> typedef struct { u_char *ip; u_char *pos; ngx_http_variable_value_t *sp; ngx_str_t buf; ngx_str_t line; /* the start of the rewritten arguments */ u_char *args; unsigned flushed:1; unsigned skip:1; unsigned quote:1; unsigned is_args:1; unsigned log:1; ngx_int_t status; ngx_http_request_t *request; } ngx_http_script_engine_t; typedef struct { ngx_conf_t *cf; ngx_str_t *source; ngx_array_t **flushes; ngx_array_t **lengths; ngx_array_t **values; ngx_uint_t variables; ngx_uint_t ncaptures; ngx_uint_t captures_mask; ngx_uint_t size; void *main; unsigned compile_args:1; unsigned complete_lengths:1; unsigned complete_values:1; unsigned zero:1; unsigned conf_prefix:1; unsigned root_prefix:1; unsigned dup_capture:1; unsigned args:1; } ngx_http_script_compile_t; typedef struct { ngx_str_t value; ngx_uint_t *flushes; void *lengths; void *values; union { size_t size; } u; } ngx_http_complex_value_t; typedef struct { ngx_conf_t *cf; ngx_str_t *value; ngx_http_complex_value_t *complex_value; unsigned zero:1; unsigned conf_prefix:1; unsigned root_prefix:1; } ngx_http_compile_complex_value_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_engine_t *e); 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; typedef struct { ngx_http_script_code_pt code; ngx_http_set_variable_pt handler; uintptr_t data; } ngx_http_script_var_handler_code_t; typedef struct { ngx_http_script_code_pt code; uintptr_t n; } ngx_http_script_copy_capture_code_t; #if (NGX_PCRE) typedef struct { ngx_http_script_code_pt code; ngx_http_regex_t *regex; ngx_array_t *lengths; uintptr_t size; uintptr_t status; uintptr_t next; unsigned test:1; unsigned negative_test:1; unsigned uri:1; unsigned args:1; /* add the r->args to the new arguments */ unsigned add_args:1; unsigned redirect:1; unsigned break_cycle:1; ngx_str_t name; } ngx_http_script_regex_code_t; typedef struct { ngx_http_script_code_pt code; unsigned uri:1; unsigned args:1; /* add the r->args to the new arguments */ unsigned add_args:1; unsigned redirect:1; } ngx_http_script_regex_end_code_t; #endif typedef struct { ngx_http_script_code_pt code; uintptr_t conf_prefix; } ngx_http_script_full_name_code_t; typedef struct { ngx_http_script_code_pt code; uintptr_t status; ngx_http_complex_value_t text; } ngx_http_script_return_code_t; typedef enum { ngx_http_script_file_plain = 0, ngx_http_script_file_not_plain, ngx_http_script_file_dir, ngx_http_script_file_not_dir, ngx_http_script_file_exists, ngx_http_script_file_not_exists, ngx_http_script_file_exec, ngx_http_script_file_not_exec } 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; void **loc_conf; } ngx_http_script_if_code_t; typedef struct { ngx_http_script_code_pt code; ngx_array_t *lengths; } ngx_http_script_complex_value_code_t; typedef struct { ngx_http_script_code_pt code; uintptr_t value; uintptr_t text_len; uintptr_t text_data; } ngx_http_script_value_code_t; void ngx_http_script_flush_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val); ngx_int_t ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val, ngx_str_t *value); size_t ngx_http_complex_value_size(ngx_http_request_t *r, ngx_http_complex_value_t *val, size_t default_value); ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv); char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_http_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates); ngx_int_t ngx_http_test_required_predicates(ngx_http_request_t *r, ngx_array_t *predicates); char *ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value); ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc); u_char *ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value, void *code_lengths, size_t reserved, void *code_values); void ngx_http_script_flush_no_cacheable_variables(ngx_http_request_t *r, ngx_array_t *indices); void *ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size); void *ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code); size_t ngx_http_script_copy_len_code(ngx_http_script_engine_t *e); void ngx_http_script_copy_code(ngx_http_script_engine_t *e); size_t ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e); void ngx_http_script_copy_var_code(ngx_http_script_engine_t *e); size_t ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e); void ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e); size_t ngx_http_script_mark_args_code(ngx_http_script_engine_t *e); void ngx_http_script_start_args_code(ngx_http_script_engine_t *e); #if (NGX_PCRE) void ngx_http_script_regex_start_code(ngx_http_script_engine_t *e); void ngx_http_script_regex_end_code(ngx_http_script_engine_t *e); #endif void ngx_http_script_return_code(ngx_http_script_engine_t *e); void ngx_http_script_break_code(ngx_http_script_engine_t *e); 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); void ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e); void ngx_http_script_var_code(ngx_http_script_engine_t *e); void ngx_http_script_nop_code(ngx_http_script_engine_t *e); #endif /* _NGX_HTTP_SCRIPT_H_INCLUDED_ */