Perl: reworked perl module to pass ctx instead of request.

This ensures that correct ctx is always available, including after
filter finalization.  In particular, this fixes a segmentation fault
with the following configuration:

    location / {
        image_filter test;

        perl 'sub {
            my $r = shift;
            $r->send_http_header();
            $r->print("foo\n");
            $r->print("bar\n");
        }';
    }

This also seems to be the only way to correctly handle filter finalization
in various complex cases, for example, when embedded perl is used both
in the original handler and in an error page called after filter
finalization.
This commit is contained in:
Maxim Dounin 2019-07-12 11:29:22 +03:00
parent 792128b7f5
commit 1689e8a02a
3 changed files with 114 additions and 94 deletions

View file

@ -15,8 +15,10 @@
#include "XSUB.h" #include "XSUB.h"
#define ngx_http_perl_set_request(r) \ #define ngx_http_perl_set_request(r, ctx) \
r = INT2PTR(ngx_http_request_t *, SvIV((SV *) SvRV(ST(0)))) \
ctx = INT2PTR(ngx_http_perl_ctx_t *, SvIV((SV *) SvRV(ST(0)))); \
r = ctx->request
#define ngx_http_perl_set_targ(p, len) \ #define ngx_http_perl_set_targ(p, len) \
@ -64,14 +66,12 @@ ngx_http_perl_sv2str(pTHX_ ngx_http_request_t *r, ngx_str_t *s, SV *sv)
static ngx_int_t static ngx_int_t
ngx_http_perl_output(ngx_http_request_t *r, ngx_buf_t *b) ngx_http_perl_output(ngx_http_request_t *r, ngx_http_perl_ctx_t *ctx,
ngx_buf_t *b)
{ {
ngx_chain_t out; ngx_chain_t out;
#if (NGX_HTTP_SSI) #if (NGX_HTTP_SSI)
ngx_chain_t *cl; ngx_chain_t *cl;
ngx_http_perl_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
if (ctx->ssi) { if (ctx->ssi) {
cl = ngx_alloc_chain_link(r->pool); cl = ngx_alloc_chain_link(r->pool);
@ -105,9 +105,10 @@ void
status(r, code) status(r, code)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
r->headers_out.status = SvIV(ST(1)); r->headers_out.status = SvIV(ST(1));
@ -121,10 +122,11 @@ void
send_http_header(r, ...) send_http_header(r, ...)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
SV *sv; ngx_http_perl_ctx_t *ctx;
SV *sv;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (r->headers_out.status == 0) { if (r->headers_out.status == 0) {
r->headers_out.status = NGX_HTTP_OK; r->headers_out.status = NGX_HTTP_OK;
@ -157,9 +159,10 @@ header_only(r)
CODE: CODE:
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
sv_upgrade(TARG, SVt_IV); sv_upgrade(TARG, SVt_IV);
sv_setiv(TARG, r->header_only); sv_setiv(TARG, r->header_only);
@ -172,9 +175,10 @@ uri(r)
CODE: CODE:
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
ngx_http_perl_set_targ(r->uri.data, r->uri.len); ngx_http_perl_set_targ(r->uri.data, r->uri.len);
ST(0) = TARG; ST(0) = TARG;
@ -185,9 +189,10 @@ args(r)
CODE: CODE:
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
ngx_http_perl_set_targ(r->args.data, r->args.len); ngx_http_perl_set_targ(r->args.data, r->args.len);
ST(0) = TARG; ST(0) = TARG;
@ -198,9 +203,10 @@ request_method(r)
CODE: CODE:
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
ngx_http_perl_set_targ(r->method_name.data, r->method_name.len); ngx_http_perl_set_targ(r->method_name.data, r->method_name.len);
ST(0) = TARG; ST(0) = TARG;
@ -211,9 +217,10 @@ remote_addr(r)
CODE: CODE:
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
ngx_http_perl_set_targ(r->connection->addr_text.data, ngx_http_perl_set_targ(r->connection->addr_text.data,
r->connection->addr_text.len); r->connection->addr_text.len);
@ -226,6 +233,7 @@ header_in(r, key)
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
SV *key; SV *key;
u_char *p, *lowcase_key, *value, sep; u_char *p, *lowcase_key, *value, sep;
STRLEN len; STRLEN len;
@ -237,7 +245,7 @@ header_in(r, key)
ngx_http_header_t *hh; ngx_http_header_t *hh;
ngx_http_core_main_conf_t *cmcf; ngx_http_core_main_conf_t *cmcf;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
key = ST(1); key = ST(1);
@ -374,13 +382,12 @@ has_request_body(r, next)
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx; ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) { if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
XSRETURN_UNDEF; XSRETURN_UNDEF;
} }
ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
ctx->next = SvRV(ST(1)); ctx->next = SvRV(ST(1));
r->request_body_in_single_buf = 1; r->request_body_in_single_buf = 1;
@ -404,13 +411,14 @@ request_body(r)
CODE: CODE:
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
u_char *p, *data; ngx_http_perl_ctx_t *ctx;
size_t len; u_char *p, *data;
ngx_buf_t *buf; size_t len;
ngx_chain_t *cl; ngx_buf_t *buf;
ngx_chain_t *cl;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (r->request_body == NULL if (r->request_body == NULL
|| r->request_body->temp_file || r->request_body->temp_file
@ -465,9 +473,10 @@ request_body_file(r)
CODE: CODE:
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (r->request_body == NULL || r->request_body->temp_file == NULL) { if (r->request_body == NULL || r->request_body->temp_file == NULL) {
XSRETURN_UNDEF; XSRETURN_UNDEF;
@ -483,9 +492,10 @@ void
discard_request_body(r) discard_request_body(r)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
ngx_http_discard_request_body(r); ngx_http_discard_request_body(r);
@ -494,12 +504,13 @@ void
header_out(r, key, value) header_out(r, key, value)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
SV *key; ngx_http_perl_ctx_t *ctx;
SV *value; SV *key;
ngx_table_elt_t *header; SV *value;
ngx_table_elt_t *header;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
key = ST(1); key = ST(1);
value = ST(2); value = ST(2);
@ -542,13 +553,12 @@ filename(r)
CODE: CODE:
dXSTARG; dXSTARG;
size_t root;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx; ngx_http_perl_ctx_t *ctx;
size_t root;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
if (ctx->filename.data) { if (ctx->filename.data) {
goto done; goto done;
} }
@ -571,15 +581,16 @@ void
print(r, ...) print(r, ...)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
SV *sv; ngx_http_perl_ctx_t *ctx;
int i; SV *sv;
u_char *p; int i;
size_t size; u_char *p;
STRLEN len; size_t size;
ngx_buf_t *b; STRLEN len;
ngx_buf_t *b;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (items == 2) { if (items == 2) {
@ -660,7 +671,7 @@ print(r, ...)
out: out:
(void) ngx_http_perl_output(r, b); (void) ngx_http_perl_output(r, ctx, b);
void void
@ -668,6 +679,7 @@ sendfile(r, filename, offset = -1, bytes = 0)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
char *filename; char *filename;
off_t offset; off_t offset;
size_t bytes; size_t bytes;
@ -676,7 +688,7 @@ sendfile(r, filename, offset = -1, bytes = 0)
ngx_open_file_info_t of; ngx_open_file_info_t of;
ngx_http_core_loc_conf_t *clcf; ngx_http_core_loc_conf_t *clcf;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
filename = SvPV_nolen(ST(1)); filename = SvPV_nolen(ST(1));
@ -750,17 +762,18 @@ sendfile(r, filename, offset = -1, bytes = 0)
b->file->log = r->connection->log; b->file->log = r->connection->log;
b->file->directio = of.is_directio; b->file->directio = of.is_directio;
(void) ngx_http_perl_output(r, b); (void) ngx_http_perl_output(r, ctx, b);
void void
flush(r) flush(r)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_buf_t *b; ngx_http_perl_ctx_t *ctx;
ngx_buf_t *b;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
b = ngx_calloc_buf(r->pool); b = ngx_calloc_buf(r->pool);
if (b == NULL) { if (b == NULL) {
@ -771,7 +784,7 @@ flush(r)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->flush"); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->flush");
(void) ngx_http_perl_output(r, b); (void) ngx_http_perl_output(r, ctx, b);
XSRETURN_EMPTY; XSRETURN_EMPTY;
@ -781,16 +794,14 @@ internal_redirect(r, uri)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
SV *uri; SV *uri;
ngx_uint_t i; ngx_uint_t i;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
uri = ST(1); uri = ST(1);
ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) { if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) {
XSRETURN_EMPTY; XSRETURN_EMPTY;
} }
@ -811,9 +822,10 @@ void
allow_ranges(r) allow_ranges(r)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
r->allow_ranges = 1; r->allow_ranges = 1;
@ -823,13 +835,14 @@ unescape(r, text, type = 0)
CODE: CODE:
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
SV *text; ngx_http_perl_ctx_t *ctx;
int type; SV *text;
u_char *p, *dst, *src; int type;
STRLEN len; u_char *p, *dst, *src;
STRLEN len;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
text = ST(1); text = ST(1);
@ -858,16 +871,16 @@ variable(r, name, value = NULL)
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
SV *name, *value; SV *name, *value;
u_char *p, *lowcase; u_char *p, *lowcase;
STRLEN len; STRLEN len;
ngx_str_t var, val; ngx_str_t var, val;
ngx_uint_t i, hash; ngx_uint_t i, hash;
ngx_http_perl_var_t *v; ngx_http_perl_var_t *v;
ngx_http_perl_ctx_t *ctx;
ngx_http_variable_value_t *vv; ngx_http_variable_value_t *vv;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
name = ST(1); name = ST(1);
@ -919,8 +932,6 @@ variable(r, name, value = NULL)
if (vv->not_found) { if (vv->not_found) {
ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
if (ctx->variables) { if (ctx->variables) {
v = ctx->variables->elts; v = ctx->variables->elts;
@ -991,18 +1002,16 @@ sleep(r, sleep, next)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_msec_t sleep;
ngx_http_perl_ctx_t *ctx; ngx_http_perl_ctx_t *ctx;
ngx_msec_t sleep;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
sleep = (ngx_msec_t) SvIV(ST(1)); sleep = (ngx_msec_t) SvIV(ST(1));
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"perl sleep: %M", sleep); "perl sleep: %M", sleep);
ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
ctx->next = SvRV(ST(2)); ctx->next = SvRV(ST(2));
r->connection->write->delayed = 1; r->connection->write->delayed = 1;
@ -1016,13 +1025,14 @@ void
log_error(r, err, msg) log_error(r, err, msg)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
SV *err, *msg; ngx_http_perl_ctx_t *ctx;
u_char *p; SV *err, *msg;
STRLEN len; u_char *p;
ngx_err_t e; STRLEN len;
ngx_err_t e;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
err = ST(1); err = ST(1);

View file

@ -43,7 +43,8 @@ static PerlInterpreter *ngx_http_perl_create_interpreter(ngx_conf_t *cf,
static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires,
ngx_log_t *log); ngx_log_t *log);
static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r,
HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv); ngx_http_perl_ctx_t *ctx, HV *nginx, SV *sub, SV **args,
ngx_str_t *handler, ngx_str_t *rv);
static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv); static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv);
static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf); static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf);
@ -199,6 +200,8 @@ ngx_http_perl_handle_request(ngx_http_request_t *r)
} }
ngx_http_set_ctx(r, ctx, ngx_http_perl_module); ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
ctx->request = r;
} }
pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
@ -220,8 +223,8 @@ ngx_http_perl_handle_request(ngx_http_request_t *r)
ctx->next = NULL; ctx->next = NULL;
} }
rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sub, NULL, handler, rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, sub, NULL,
NULL); handler, NULL);
} }
@ -309,6 +312,8 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
} }
ngx_http_set_ctx(r, ctx, ngx_http_perl_module); ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
ctx->request = r;
} }
pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
@ -321,7 +326,7 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
PERL_SET_CONTEXT(pmcf->perl); PERL_SET_CONTEXT(pmcf->perl);
PERL_SET_INTERP(pmcf->perl); PERL_SET_INTERP(pmcf->perl);
rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, pv->sub, NULL, rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, pv->sub, NULL,
&pv->handler, &value); &pv->handler, &value);
} }
@ -372,6 +377,8 @@ ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx,
} }
ngx_http_set_ctx(r, ctx, ngx_http_perl_module); ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
ctx->request = r;
} }
pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
@ -430,8 +437,8 @@ ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx,
asv = NULL; asv = NULL;
} }
rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, asv, handler, rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, sv, asv,
NULL); handler, NULL);
SvREFCNT_dec(sv); SvREFCNT_dec(sv);
@ -667,8 +674,9 @@ ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log)
static ngx_int_t static ngx_int_t
ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub, ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r,
SV **args, ngx_str_t *handler, ngx_str_t *rv) ngx_http_perl_ctx_t *ctx, HV *nginx, SV *sub, SV **args,
ngx_str_t *handler, ngx_str_t *rv)
{ {
SV *sv; SV *sv;
int n, status; int n, status;
@ -687,7 +695,7 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub,
PUSHMARK(sp); PUSHMARK(sp);
sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(r))), nginx)); sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(ctx))), nginx));
XPUSHs(sv); XPUSHs(sv);
if (args) { if (args) {

View file

@ -21,6 +21,8 @@
typedef ngx_http_request_t *nginx; typedef ngx_http_request_t *nginx;
typedef struct { typedef struct {
ngx_http_request_t *request;
ngx_str_t filename; ngx_str_t filename;
ngx_str_t redirect_uri; ngx_str_t redirect_uri;
ngx_str_t redirect_args; ngx_str_t redirect_args;